blob: 8d5931713955f316acf7076daf2a1d83b9a01b3c [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/keyboard_backlight_controller.h"
#include <cmath>
#include <string>
#include <gtest/gtest.h>
#include "power_manager/common/clock.h"
#include "power_manager/common/fake_prefs.h"
#include "power_manager/common/power_constants.h"
#include "power_manager/common/util.h"
#include "power_manager/powerd/policy/backlight_controller.h"
#include "power_manager/powerd/policy/backlight_controller_observer_stub.h"
#include "power_manager/powerd/policy/backlight_controller_stub.h"
#include "power_manager/powerd/system/ambient_light_sensor_stub.h"
#include "power_manager/powerd/system/backlight_stub.h"
#include "power_manager/powerd/system/dbus_wrapper_stub.h"
#include "power_manager/proto_bindings/policy.pb.h"
namespace power_manager {
namespace policy {
class KeyboardBacklightControllerTest : public ::testing::Test {
public:
KeyboardBacklightControllerTest()
: max_backlight_level_(100),
initial_backlight_level_(50),
pass_light_sensor_(true),
initial_als_lux_(0),
initial_tablet_mode_(TabletMode::UNSUPPORTED),
als_steps_pref_("20.0 -1 50\n50.0 35 75\n75.0 60 -1"),
user_steps_pref_("0.0\n10.0\n40.0\n60.0\n100.0"),
no_als_brightness_pref_(40.0),
detect_hover_pref_(0),
turn_on_for_user_activity_pref_(0),
keep_on_ms_pref_(0),
keep_on_during_video_ms_pref_(0),
backlight_(max_backlight_level_,
initial_backlight_level_,
system::BacklightInterface::BrightnessScale::kUnknown),
light_sensor_(initial_als_lux_),
test_api_(&controller_) {
test_api_.clock()->set_current_time_for_testing(
base::TimeTicks::FromInternalValue(1000));
controller_.AddObserver(&observer_);
}
~KeyboardBacklightControllerTest() override {
controller_.RemoveObserver(&observer_);
}
// Initializes |controller_|.
virtual void Init() {
backlight_.set_max_level(max_backlight_level_);
backlight_.set_current_level(initial_backlight_level_);
light_sensor_.set_lux(initial_als_lux_);
prefs_.SetString(kKeyboardBacklightAlsStepsPref, als_steps_pref_);
prefs_.SetString(kKeyboardBacklightUserStepsPref, user_steps_pref_);
prefs_.SetDouble(kKeyboardBacklightNoAlsBrightnessPref,
no_als_brightness_pref_);
prefs_.SetDouble(kAlsSmoothingConstantPref, 1.0);
prefs_.SetInt64(kDetectHoverPref, detect_hover_pref_);
prefs_.SetInt64(kKeyboardBacklightTurnOnForUserActivityPref,
turn_on_for_user_activity_pref_);
prefs_.SetInt64(kKeyboardBacklightKeepOnMsPref, keep_on_ms_pref_);
prefs_.SetInt64(kKeyboardBacklightKeepOnDuringVideoMsPref,
keep_on_during_video_ms_pref_);
controller_.Init(&backlight_, &prefs_,
pass_light_sensor_ ? &light_sensor_ : nullptr,
&dbus_wrapper_, &display_backlight_controller_,
initial_lid_state_, initial_tablet_mode_);
}
protected:
// Returns the hardware-specific brightness level that should be used when the
// display is dimmed.
int64_t GetDimmedLevel() {
return static_cast<int64_t>(lround(
KeyboardBacklightController::kDimPercent / 100 * max_backlight_level_));
}
// Advances |controller_|'s clock by |interval|.
void AdvanceTime(const base::TimeDelta& interval) {
test_api_.clock()->set_current_time_for_testing(
test_api_.clock()->GetCurrentTime() + interval);
}
// Calls the IncreaseKeyboardBrightness D-Bus method.
void CallIncreaseKeyboardBrightness() {
dbus::MethodCall method_call(kPowerManagerInterface,
kIncreaseKeyboardBrightnessMethod);
ASSERT_TRUE(dbus_wrapper_.CallExportedMethodSync(&method_call));
}
// Calls the DecreaseKeyboardBrightness D-Bus method.
void CallDecreaseKeyboardBrightness() {
dbus::MethodCall method_call(kPowerManagerInterface,
kDecreaseKeyboardBrightnessMethod);
ASSERT_TRUE(dbus_wrapper_.CallExportedMethodSync(&method_call));
}
// Calls the GetKeyboardBrightnessPercent D-Bus method and returns the
// percentage from the reply. Adds a failure and returns 0 on error.
double CallGetKeyboardBrightnessPercent() {
dbus::MethodCall method_call(kPowerManagerInterface,
kGetKeyboardBrightnessPercentMethod);
std::unique_ptr<dbus::Response> response =
dbus_wrapper_.CallExportedMethodSync(&method_call);
if (!response) {
ADD_FAILURE() << kGetKeyboardBrightnessPercentMethod << " call failed";
return 0.0;
}
double percent = 0.0;
if (!dbus::MessageReader(response.get()).PopDouble(&percent))
ADD_FAILURE() << "Bad " << kGetKeyboardBrightnessPercentMethod << " arg";
return percent;
}
BacklightControllerStub display_backlight_controller_;
// Max and initial brightness levels for |backlight_|.
int64_t max_backlight_level_;
int64_t initial_backlight_level_;
// Should |light_sensor_| be passed to |controller_|?
bool pass_light_sensor_;
// Initial lux level reported by |light_sensor_|.
int initial_als_lux_;
// Initial lid state and tablet mode passed to |controller_|.
LidState initial_lid_state_ = LidState::NOT_PRESENT;
TabletMode initial_tablet_mode_;
// Values for various preferences. These can be changed by tests before
// Init() is called.
std::string als_steps_pref_;
std::string user_steps_pref_;
double no_als_brightness_pref_;
int64_t detect_hover_pref_;
int64_t turn_on_for_user_activity_pref_;
int64_t keep_on_ms_pref_;
int64_t keep_on_during_video_ms_pref_;
FakePrefs prefs_;
system::BacklightStub backlight_;
system::AmbientLightSensorStub light_sensor_;
system::DBusWrapperStub dbus_wrapper_;
BacklightControllerObserverStub observer_;
KeyboardBacklightController controller_;
KeyboardBacklightController::TestApi test_api_;
};
TEST_F(KeyboardBacklightControllerTest, GetBrightnessPercent) {
Init();
// GetKeyboardBrightnessPercent should initially return the backlight's
// starting level. (It's safe to compare levels and percents since we're
// using a [0, 100] range to make things simpler.)
EXPECT_DOUBLE_EQ(static_cast<double>(initial_backlight_level_),
CallGetKeyboardBrightnessPercent());
// After increasing the brightness, the new level should be returned.
CallIncreaseKeyboardBrightness();
EXPECT_DOUBLE_EQ(static_cast<double>(backlight_.current_level()),
CallGetKeyboardBrightnessPercent());
}
TEST_F(KeyboardBacklightControllerTest, GetBrightnessPercentWithScaling) {
user_steps_pref_ = "0.0\n5.0\n20.0\n30.0\n50.0";
initial_backlight_level_ = 0;
Init();
// Level 0 5 20 30 50
// Raw percentages 0.0 5.0 20.0 30.0 50.0
// Scaled percentages 0.0 10.0 40.0 60.0 100.0
std::vector<double> scaled_percents{0.0, 10.0, 40.0, 60.0, 100.0};
std::vector<int> levels{0, 5, 20, 30, 50};
for (size_t i = 0; i < levels.size(); i++) {
EXPECT_DOUBLE_EQ(scaled_percents[i], CallGetKeyboardBrightnessPercent());
EXPECT_EQ(levels[i], backlight_.current_level());
CallIncreaseKeyboardBrightness();
}
}
TEST_F(KeyboardBacklightControllerTest, TurnOffForFullscreenVideo) {
als_steps_pref_ = "20.0 -1 50\n50.0 35 75\n75.0 60 -1";
user_steps_pref_ = "0.0\n100.0";
Init();
controller_.HandleSessionStateChange(SessionState::STARTED);
light_sensor_.NotifyObservers();
ASSERT_EQ(20, backlight_.current_level());
// Non-fullscreen video shouldn't turn off the backlight.
controller_.HandleVideoActivity(false);
EXPECT_EQ(20, backlight_.current_level());
// Fullscreen video should turn it off.
controller_.HandleVideoActivity(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// If the video switches to non-fullscreen, the backlight should be turned on.
controller_.HandleVideoActivity(false);
EXPECT_EQ(20, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Let fullscreen video turn it off again.
controller_.HandleVideoActivity(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// If the timeout fires to indicate that video has stopped, the backlight
// should be turned on.
ASSERT_TRUE(test_api_.TriggerVideoTimeout());
EXPECT_EQ(20, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Fullscreen video should be ignored when the user isn't logged in.
controller_.HandleSessionStateChange(SessionState::STOPPED);
controller_.HandleVideoActivity(true);
EXPECT_EQ(20, backlight_.current_level());
// It should also be ignored after the brightness has been set by the user.
controller_.HandleSessionStateChange(SessionState::STARTED);
controller_.HandleVideoActivity(true);
EXPECT_EQ(0, backlight_.current_level());
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
controller_.HandleVideoActivity(true);
EXPECT_EQ(100, backlight_.current_level());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(0, backlight_.current_level());
ASSERT_TRUE(test_api_.TriggerVideoTimeout());
EXPECT_EQ(0, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, OnAmbientLightUpdated) {
initial_backlight_level_ = 20;
als_steps_pref_ = "20.0 -1 50\n50.0 35 75\n75.0 60 -1";
Init();
ASSERT_EQ(20, backlight_.current_level());
EXPECT_EQ(0, controller_.GetNumAmbientLightSensorAdjustments());
// ALS returns bad value.
light_sensor_.set_lux(-1);
light_sensor_.NotifyObservers();
EXPECT_EQ(20, backlight_.current_level());
// ALS returns a value in the middle of the initial step.
light_sensor_.set_lux(25);
light_sensor_.NotifyObservers();
EXPECT_EQ(20, backlight_.current_level());
// First increase; hysteresis not overcome.
light_sensor_.set_lux(80);
light_sensor_.NotifyObservers();
EXPECT_EQ(20, backlight_.current_level());
// Second increase; hysteresis overcome. The lux is high enough that the
// controller should skip over the middle step and use the top step.
light_sensor_.NotifyObservers();
EXPECT_EQ(75, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
EXPECT_EQ(1, controller_.GetNumAmbientLightSensorAdjustments());
// First decrease; hysteresis not overcome.
light_sensor_.set_lux(50);
light_sensor_.NotifyObservers();
EXPECT_EQ(75, backlight_.current_level());
// Second decrease; hysteresis overcome. The controller should decrease
// to the middle step.
light_sensor_.NotifyObservers();
EXPECT_EQ(50, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
EXPECT_EQ(2, controller_.GetNumAmbientLightSensorAdjustments());
// The count should be reset after a new session starts.
controller_.HandleSessionStateChange(SessionState::STARTED);
EXPECT_EQ(0, controller_.GetNumAmbientLightSensorAdjustments());
}
TEST_F(KeyboardBacklightControllerTest, ChangeStates) {
// Configure a single step for ALS and three steps for user control.
als_steps_pref_ = "50.0 -1 -1";
user_steps_pref_ = "0.0\n10.0\n100.0";
initial_backlight_level_ = 50;
Init();
light_sensor_.NotifyObservers();
ASSERT_EQ(50, backlight_.current_level());
// Requests to dim the backlight and turn it off should be honored, as
// should changes to turn it back on and undim.
controller_.SetDimmedForInactivity(true);
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.SetOffForInactivity(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.SetOffForInactivity(false);
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.SetDimmedForInactivity(false);
EXPECT_EQ(50, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Send an increase request to switch to user control.
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Go through the same sequence of state changes and check that the
// user-control dimming level is used.
controller_.SetDimmedForInactivity(true);
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.SetOffForInactivity(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.SetOffForInactivity(false);
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.SetDimmedForInactivity(false);
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, DontBrightenToDim) {
// Set the bottom ALS step to 2%.
als_steps_pref_ = "2.0 -1 60\n80.0 40 -1";
initial_als_lux_ = 2;
Init();
ASSERT_LT(initial_als_lux_, GetDimmedLevel());
light_sensor_.NotifyObservers();
ASSERT_EQ(initial_als_lux_, backlight_.current_level());
// The controller should never increase the brightness level when dimming.
controller_.SetDimmedForInactivity(true);
EXPECT_EQ(initial_als_lux_, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, DeferChangesWhileDimmed) {
als_steps_pref_ = "20.0 -1 60\n80.0 40 -1";
initial_als_lux_ = 20;
Init();
light_sensor_.NotifyObservers();
ASSERT_EQ(initial_als_lux_, backlight_.current_level());
controller_.SetDimmedForInactivity(true);
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
// ALS-driven changes shouldn't be applied while the screen is dimmed.
light_sensor_.set_lux(80);
light_sensor_.NotifyObservers();
light_sensor_.NotifyObservers();
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
// The new ALS level should be used immediately after undimming, though.
controller_.SetDimmedForInactivity(false);
EXPECT_EQ(80, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, InitialUserLevelDownFirst) {
// Set user steps at 0, 10, 40, 60, and 100. The backlight should remain
// at its starting level when Init() is called.
user_steps_pref_ = "0.0\n10.0\n40.0\n60.0\n100.0";
initial_backlight_level_ = 15;
Init();
EXPECT_EQ(15, backlight_.current_level());
// After an increase request switches to user control of the brightness
// level, the controller should first choose the step (10) nearest to the
// initial level (15) and then increase to the next step (40).
CallIncreaseKeyboardBrightness();
EXPECT_EQ(40, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, InitialUserLevelUpFirst) {
// Set user steps at 0, 10, 40, 60, and 100. The backlight should remain
// at its starting level when Init() is called.
user_steps_pref_ = "0.0\n10.0\n40.0\n60.0\n100.0";
initial_backlight_level_ = 30;
Init();
EXPECT_EQ(30, backlight_.current_level());
// After an increase request switches to user control of the brightness
// level, the controller should first choose the step (40) nearest to the
// initial level (30) and then increase to the next step (60).
CallIncreaseKeyboardBrightness();
EXPECT_EQ(60, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, InitialAlsLevel) {
// Set an initial backlight level that's closest to the 60% step and
// within its lux range of [50, 90].
als_steps_pref_ = "0.0 -1 30\n30.0 20 60\n60.0 50 90\n100.0 80 -1";
initial_backlight_level_ = 55;
initial_als_lux_ = 85;
Init();
EXPECT_EQ(55, backlight_.current_level());
// After an ambient light reading, the controller should slowly
// transition to the 60% level.
light_sensor_.NotifyObservers();
EXPECT_EQ(60, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, IncreaseBrightness) {
user_steps_pref_ = "0.0\n10.0\n40.0\n60.0\n100.0";
initial_backlight_level_ = 0;
Init();
EXPECT_EQ(0, backlight_.current_level());
CallIncreaseKeyboardBrightness();
EXPECT_EQ(10, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
EXPECT_EQ(1, controller_.GetNumUserAdjustments());
CallIncreaseKeyboardBrightness();
EXPECT_EQ(40, backlight_.current_level());
EXPECT_EQ(2, controller_.GetNumUserAdjustments());
CallIncreaseKeyboardBrightness();
EXPECT_EQ(60, backlight_.current_level());
EXPECT_EQ(3, controller_.GetNumUserAdjustments());
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(4, controller_.GetNumUserAdjustments());
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(5, controller_.GetNumUserAdjustments());
// The count should be reset after a new session starts.
controller_.HandleSessionStateChange(SessionState::STARTED);
EXPECT_EQ(0, controller_.GetNumUserAdjustments());
}
TEST_F(KeyboardBacklightControllerTest, DecreaseBrightness) {
user_steps_pref_ = "0.0\n10.0\n40.0\n60.0\n100.0";
initial_backlight_level_ = 100;
Init();
EXPECT_EQ(100, backlight_.current_level());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(60, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
EXPECT_EQ(1, controller_.GetNumUserAdjustments());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(40, backlight_.current_level());
EXPECT_EQ(2, controller_.GetNumUserAdjustments());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(10, backlight_.current_level());
EXPECT_EQ(3, controller_.GetNumUserAdjustments());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(4, controller_.GetNumUserAdjustments());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(5, controller_.GetNumUserAdjustments());
}
TEST_F(KeyboardBacklightControllerTest, TurnOffWhenSuspended) {
initial_backlight_level_ = 50;
no_als_brightness_pref_ = 50;
pass_light_sensor_ = false;
Init();
controller_.SetSuspended(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(0, backlight_.current_interval().InMilliseconds());
controller_.SetSuspended(false);
EXPECT_EQ(50, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, TurnOffWhenShuttingDown) {
Init();
controller_.SetShuttingDown(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(0, backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, TurnOffWhenLidClosed) {
initial_lid_state_ = LidState::OPEN;
Init();
ASSERT_EQ(initial_backlight_level_, backlight_.current_level());
controller_.HandleLidStateChange(LidState::CLOSED);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(0, backlight_.current_interval().InMilliseconds());
// User requests to increase the brightness shouldn't turn the backlight on.
CallIncreaseKeyboardBrightness();
EXPECT_EQ(0, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, TurnOffWhenDisplayBacklightIsOff) {
als_steps_pref_ = "50.0 -1 -1";
user_steps_pref_ = "0.0\n100.0";
initial_backlight_level_ = 50;
Init();
light_sensor_.set_lux(100);
light_sensor_.NotifyObservers();
display_backlight_controller_.NotifyObservers(
10.0, BacklightBrightnessChange_Cause_USER_REQUEST);
EXPECT_EQ(50, backlight_.current_level());
// When the display backlight's brightness goes to zero while the
// keyboard backlight is using an ambient-light-derived brightness, the
// keyboard backlight should be turned off automatically.
display_backlight_controller_.NotifyObservers(
0.0, BacklightBrightnessChange_Cause_USER_REQUEST);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
display_backlight_controller_.NotifyObservers(
20.0, BacklightBrightnessChange_Cause_USER_REQUEST);
EXPECT_EQ(50, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// After switching to user control of the brightness, the keyboard
// backlight shouldn't be turned off automatically.
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
display_backlight_controller_.NotifyObservers(
0.0, BacklightBrightnessChange_Cause_USER_REQUEST);
EXPECT_EQ(100, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, Hover) {
als_steps_pref_ = "50.0 -1 -1";
user_steps_pref_ = "0.0\n100.0";
detect_hover_pref_ = 1;
keep_on_ms_pref_ = 30000;
keep_on_during_video_ms_pref_ = 3000;
Init();
controller_.HandleSessionStateChange(SessionState::STARTED);
light_sensor_.NotifyObservers();
// The backlight should initially be off since the user isn't hovering.
EXPECT_EQ(0, backlight_.current_level());
// If hovering is detected, the backlight should be turned on quickly.
controller_.HandleHoverStateChange(true);
EXPECT_EQ(50, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// It should remain on despite fullscreen video if hovering continues.
controller_.HandleVideoActivity(true);
EXPECT_EQ(50, backlight_.current_level());
// It should remain on for a short period of time if hovering stops while the
// video is still playing.
controller_.HandleHoverStateChange(false);
EXPECT_EQ(50, backlight_.current_level());
// After enough time, the backlight should turn off.
AdvanceTime(base::TimeDelta::FromMilliseconds(keep_on_during_video_ms_pref_));
ASSERT_TRUE(test_api_.TriggerTurnOffTimeout());
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Stop the video. Since the user was hovering recently, the backlight should
// turn back on.
ASSERT_TRUE(test_api_.TriggerVideoTimeout());
EXPECT_EQ(50, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// After the rest of the full timeout, the backlight should turn off slowly.
AdvanceTime(base::TimeDelta::FromMilliseconds(keep_on_ms_pref_ -
keep_on_during_video_ms_pref_));
ASSERT_TRUE(test_api_.TriggerTurnOffTimeout());
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// User activity should also turn the keyboard backlight on for the full
// delay.
controller_.HandleUserActivity(USER_ACTIVITY_OTHER);
EXPECT_EQ(50, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
AdvanceTime(base::TimeDelta::FromMilliseconds(keep_on_ms_pref_));
ASSERT_TRUE(test_api_.TriggerTurnOffTimeout());
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Increase the brightness to 100, dim for inactivity, and check that hover
// restores the user-requested level.
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
controller_.SetDimmedForInactivity(true);
EXPECT_EQ(GetDimmedLevel(), backlight_.current_level());
controller_.HandleHoverStateChange(true);
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// The backlight should stay on while hovering even if it's requested to turn
// off for inactivity.
controller_.SetOffForInactivity(true);
EXPECT_EQ(100, backlight_.current_level());
// Stop hovering and check that starting again turns the backlight on again.
controller_.HandleHoverStateChange(false);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
controller_.HandleHoverStateChange(true);
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// A notification that the system is shutting down should take precedence.
controller_.SetShuttingDown(true);
EXPECT_EQ(0, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, NoAmbientLightSensor) {
initial_backlight_level_ = 0;
no_als_brightness_pref_ = 40.0;
user_steps_pref_ = "0.0\n10.0\n100.0";
pass_light_sensor_ = false;
Init();
// The brightness should immediately transition to the level from the pref.
EXPECT_EQ(40, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Subsequent adjustments should move between the user steps.
CallIncreaseKeyboardBrightness();
EXPECT_EQ(100, backlight_.current_level());
CallDecreaseKeyboardBrightness();
EXPECT_EQ(10, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, EnableForUserActivity) {
initial_backlight_level_ = 50;
no_als_brightness_pref_ = 40.0;
user_steps_pref_ = "0.0\n100.0";
turn_on_for_user_activity_pref_ = 1;
keep_on_ms_pref_ = 30000;
pass_light_sensor_ = false;
Init();
// The backlight should turn off initially.
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// User activity should result in the backlight being turned on quickly.
controller_.HandleUserActivity(USER_ACTIVITY_OTHER);
EXPECT_EQ(40, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Advance the time and report user activity again.
AdvanceTime(base::TimeDelta::FromMilliseconds(keep_on_ms_pref_ / 2));
controller_.HandleUserActivity(USER_ACTIVITY_OTHER);
EXPECT_EQ(40, backlight_.current_level());
// The backlight should be turned off |keep_on_ms_pref_| after the last report
// of user activity.
AdvanceTime(base::TimeDelta::FromMilliseconds(keep_on_ms_pref_));
ASSERT_TRUE(test_api_.TriggerTurnOffTimeout());
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, PreemptTransitionForShutdown) {
initial_backlight_level_ = 50;
Init();
// Notify the keyboard controller that the display has been turned off (as
// happens when shutting down).
display_backlight_controller_.NotifyObservers(
0.0, BacklightBrightnessChange_Cause_OTHER);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Now notify the keyboard controller that the system is shutting down and
// check that the previous transition is preempted in favor of turning off the
// keyboard backlight immediately.
backlight_.set_transition_in_progress(true);
controller_.SetShuttingDown(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(0, backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, TurnOffWhenInTabletMode) {
// The backlight should be initially turned off if the device is already in
// tablet mode.
initial_backlight_level_ = 100;
no_als_brightness_pref_ = 100.0;
pass_light_sensor_ = false;
initial_tablet_mode_ = TabletMode::ON;
Init();
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kSlowBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// It should quickly turn on when the device leaves tablet mode.
controller_.HandleTabletModeChange(TabletMode::OFF);
EXPECT_EQ(100, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
// Going back to tablet mode should turn the backlight off again.
controller_.HandleTabletModeChange(TabletMode::ON);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(kFastBacklightTransitionMs,
backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, ForcedOff) {
initial_backlight_level_ = 50;
Init();
ASSERT_GT(backlight_.current_level(), 0);
controller_.SetForcedOff(true);
EXPECT_EQ(0, backlight_.current_level());
EXPECT_EQ(0, backlight_.current_interval().InMilliseconds());
controller_.SetForcedOff(false);
EXPECT_GT(backlight_.current_level(), 0);
EXPECT_EQ(0, backlight_.current_interval().InMilliseconds());
}
TEST_F(KeyboardBacklightControllerTest, ChangeBacklightDevice) {
// Start out without a backlight device.
user_steps_pref_ = "0.0\n50.0\n100.0";
backlight_.set_device_exists(false);
Init();
CallIncreaseKeyboardBrightness();
controller_.SetOffForInactivity(true);
// Connect a device and check that the earlier off state is applied to it.
backlight_.set_device_exists(true);
backlight_.NotifyDeviceChanged();
EXPECT_EQ(0, backlight_.current_level());
controller_.SetOffForInactivity(false);
CallIncreaseKeyboardBrightness();
CallIncreaseKeyboardBrightness();
EXPECT_EQ(max_backlight_level_, backlight_.current_level());
// Disconnect the device and check that decrease requests are ignored.
backlight_.set_device_exists(false);
backlight_.NotifyDeviceChanged();
CallDecreaseKeyboardBrightness();
// The previous 100% brightness should be reapplied to a new device with a
// different range.
backlight_.set_device_exists(true);
backlight_.set_max_level(200);
backlight_.set_current_level(100);
backlight_.NotifyDeviceChanged();
EXPECT_EQ(200, backlight_.current_level());
}
TEST_F(KeyboardBacklightControllerTest, EmptyUserSteps) {
user_steps_pref_ = "";
EXPECT_DEATH(
Init(),
"No user brightness steps defined in keyboard_backlight_user_steps");
}
TEST_F(KeyboardBacklightControllerTest, UserStepsNotStartAt0) {
user_steps_pref_ = "10.0\n50.0\n100.0";
EXPECT_DEATH(
Init(),
"keyboard_backlight_user_steps starts at 10.000000 instead of 0.0");
}
TEST_F(KeyboardBacklightControllerTest, UserStepsTooBig) {
user_steps_pref_ = "0.0\n50.0\n110.0";
EXPECT_DEATH(Init(),
"keyboard_backlight_user_steps step 110.000000 is outside "
"\\[0.0, 100.0]");
}
TEST_F(KeyboardBacklightControllerTest, UserStepsTooSmall) {
user_steps_pref_ = "0.0\n-10.0\n100.0";
EXPECT_DEATH(Init(),
"keyboard_backlight_user_steps step -10.000000 is outside "
"\\[0.0, 100.0]");
}
TEST_F(KeyboardBacklightControllerTest, UserStepsNotStrictlyIncreasing) {
user_steps_pref_ = "0.0\n0.0\n100.0";
EXPECT_DEATH(Init(),
"keyboard_backlight_user_steps is not strictly increasing");
}
} // namespace policy
} // namespace power_manager