blob: 24b50fe789461b71c755ccc31f522f8abb9e26e4 [file] [log] [blame]
// Copyright 2018 The Chromium 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 "chrome/browser/chromeos/power/auto_screen_brightness/adapter.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "base/memory/ptr_util.h"
#include "base/task/task_scheduler/task_scheduler.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_als_reader.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_brightness_monitor.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/monotone_cubic_spline.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/chromeos_features.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
#include "chromeos/dbus/power_manager/backlight.pb.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/testing_pref_store.h"
#include "components/sync_preferences/pref_service_mock_factory.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace power {
namespace auto_screen_brightness {
namespace {
// Testing modeller.
class FakeModeller : public Modeller {
public:
FakeModeller() = default;
~FakeModeller() override = default;
void InitModellerWithCurves(
const base::Optional<MonotoneCubicSpline>& global_curve,
const base::Optional<MonotoneCubicSpline>& personal_curve) {
DCHECK(!modeller_initialized_);
modeller_initialized_ = true;
if (global_curve)
global_curve_.emplace(*global_curve);
if (personal_curve)
personal_curve_.emplace(*personal_curve);
}
void ReportModelTrained(const MonotoneCubicSpline& personal_curve) {
DCHECK(modeller_initialized_);
personal_curve_.emplace(personal_curve);
for (auto& observer : observers_)
observer.OnModelTrained(personal_curve);
}
void ReportModelInitialized() {
DCHECK(modeller_initialized_);
for (auto& observer : observers_)
observer.OnModelInitialized(global_curve_, personal_curve_);
}
// Modeller overrides:
void AddObserver(Modeller::Observer* observer) override {
DCHECK(observer);
observers_.AddObserver(observer);
if (modeller_initialized_)
observer->OnModelInitialized(global_curve_, personal_curve_);
}
void RemoveObserver(Modeller::Observer* observer) override {
DCHECK(observer);
observers_.RemoveObserver(observer);
}
private:
bool modeller_initialized_ = false;
base::Optional<MonotoneCubicSpline> global_curve_;
base::Optional<MonotoneCubicSpline> personal_curve_;
base::ObserverList<Observer> observers_;
};
class TestObserver : public PowerManagerClient::Observer {
public:
TestObserver() = default;
~TestObserver() override = default;
// chromeos::PowerManagerClient::Observer overrides:
void ScreenBrightnessChanged(
const power_manager::BacklightBrightnessChange& change) override {
++num_changes_;
change_ = change;
}
double GetBrightnessPercent() const { return change_.percent(); }
int num_changes() const { return num_changes_; }
power_manager::BacklightBrightnessChange_Cause GetCause() const {
return change_.cause();
}
private:
int num_changes_ = 0;
power_manager::BacklightBrightnessChange change_;
};
} // namespace
class AdapterTest : public testing::Test {
public:
AdapterTest()
: thread_bundle_(
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {
chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
std::make_unique<chromeos::FakePowerManagerClient>());
power_manager::SetBacklightBrightnessRequest request;
request.set_percent(1);
chromeos::DBusThreadManager::Get()
->GetPowerManagerClient()
->SetScreenBrightness(request);
thread_bundle_.RunUntilIdle();
chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
&test_observer_);
global_curve_.emplace(MonotoneCubicSpline({-4, 12, 20}, {30, 80, 100}));
personal_curve_.emplace(MonotoneCubicSpline({-4, 12, 20}, {20, 60, 100}));
}
~AdapterTest() override {
base::TaskScheduler::GetInstance()->FlushForTesting();
}
void SetUpAdapter(const std::map<std::string, std::string>& params,
bool brightness_set_by_policy = false) {
sync_preferences::PrefServiceMockFactory factory;
factory.set_user_prefs(base::WrapRefCounted(new TestingPrefStore()));
scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
new user_prefs::PrefRegistrySyncable);
chromeos::power::auto_screen_brightness::MetricsReporter::
RegisterLocalStatePrefs(registry.get());
// Same default values as used in the actual pref store.
registry->RegisterIntegerPref(ash::prefs::kPowerAcScreenBrightnessPercent,
-1, PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(
ash::prefs::kPowerBatteryScreenBrightnessPercent, -1,
PrefRegistry::PUBLIC);
sync_preferences::PrefServiceSyncable* regular_prefs =
factory.CreateSyncable(registry.get()).release();
RegisterUserProfilePrefs(registry.get());
if (brightness_set_by_policy) {
regular_prefs->SetInteger(ash::prefs::kPowerAcScreenBrightnessPercent,
10);
regular_prefs->SetInteger(
ash::prefs::kPowerBatteryScreenBrightnessPercent, 10);
}
CHECK(temp_dir_.CreateUniqueTempDir());
TestingProfile::Builder profile_builder;
profile_builder.SetProfileName("testuser@gmail.com");
profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestProfile"));
profile_builder.SetPrefService(base::WrapUnique(regular_prefs));
profile_ = profile_builder.Build();
base::test::ScopedFeatureList scoped_feature_list;
if (!params.empty()) {
scoped_feature_list.InitAndEnableFeatureWithParameters(
features::kAutoScreenBrightness, params);
}
adapter_ = std::make_unique<Adapter>(
profile_.get(), &fake_als_reader_, &fake_brightness_monitor_,
&fake_modeller_, nullptr /* metrics_reporter */,
chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
adapter_->SetTickClockForTesting(thread_bundle_.GetMockTickClock());
}
void Init(AlsReader::AlsInitStatus als_reader_status,
BrightnessMonitor::Status brightness_monitor_status,
const base::Optional<MonotoneCubicSpline>& global_curve,
const base::Optional<MonotoneCubicSpline>& personal_curve,
const std::map<std::string, std::string>& params,
bool brightness_set_by_policy = false) {
fake_als_reader_.set_als_init_status(als_reader_status);
fake_brightness_monitor_.set_status(brightness_monitor_status);
fake_modeller_.InitModellerWithCurves(global_curve, personal_curve);
SetUpAdapter(params, brightness_set_by_policy);
thread_bundle_.RunUntilIdle();
}
protected:
content::TestBrowserThreadBundle thread_bundle_;
TestObserver test_observer_;
base::ScopedTempDir temp_dir_;
std::unique_ptr<TestingProfile> profile_;
base::Optional<MonotoneCubicSpline> global_curve_;
base::Optional<MonotoneCubicSpline> personal_curve_;
FakeAlsReader fake_als_reader_;
FakeBrightnessMonitor fake_brightness_monitor_;
FakeModeller fake_modeller_;
base::HistogramTester histogram_tester_;
const std::map<std::string, std::string> default_params_ = {
{"brightening_lux_threshold_ratio", "0.1"},
{"darkening_lux_threshold_ratio", "0.2"},
{"immediate_brightening_lux_threshold_ratio", "3"},
{"immediate_darkening_lux_threshold_ratio", "1"},
{"update_brightness_on_startup", "true"},
{"min_seconds_between_brightness_changes", "10"},
{"model_curve", "2"},
};
std::unique_ptr<Adapter> adapter_;
private:
DISALLOW_COPY_AND_ASSIGN(AdapterTest);
};
// AlsReader is |kDisabled| when Adapter is created.
TEST_F(AdapterTest, AlsReaderDisabledOnInit) {
Init(AlsReader::AlsInitStatus::kDisabled, BrightnessMonitor::Status::kSuccess,
global_curve_, base::nullopt /* personal_curve */, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
// BrightnessMonitor is |kDisabled| when Adapter is created.
TEST_F(AdapterTest, BrightnessMonitorDisabledOnInit) {
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kDisabled,
global_curve_, base::nullopt /* personal_curve */, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
// Modeller is |kDisabled| when Adapter is created.
TEST_F(AdapterTest, ModellerDisabledOnInit) {
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
base::nullopt /* global_curve */, base::nullopt /* personal_curve */,
default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
// AlsReader is |kDisabled| on later notification.
TEST_F(AdapterTest, AlsReaderDisabledOnNotification) {
Init(AlsReader::AlsInitStatus::kInProgress,
BrightnessMonitor::Status::kSuccess, global_curve_,
base::nullopt /* personal_curve */, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled);
fake_als_reader_.ReportReaderInitialized();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
// AlsReader is |kSuccess| on later notification.
TEST_F(AdapterTest, AlsReaderEnabledOnNotification) {
Init(AlsReader::AlsInitStatus::kInProgress,
BrightnessMonitor::Status::kSuccess, global_curve_,
base::nullopt /* personal_curve */, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
fake_als_reader_.ReportReaderInitialized();
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_FALSE(adapter_->GetPersonalCurveForTesting());
}
// BrightnessMonitor is |kDisabled| on later notification.
TEST_F(AdapterTest, BrightnessMonitorDisabledOnNotification) {
Init(AlsReader::AlsInitStatus::kSuccess,
BrightnessMonitor::Status::kInitializing, global_curve_,
base::nullopt /* personal_curve */, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled);
fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
// BrightnessMonitor is |kSuccess| on later notification.
TEST_F(AdapterTest, BrightnessMonitorEnabledOnNotification) {
Init(AlsReader::AlsInitStatus::kSuccess,
BrightnessMonitor::Status::kInitializing, global_curve_,
base::nullopt /* personal_curve */, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_FALSE(adapter_->GetPersonalCurveForTesting());
}
// Modeller is |kDisabled| on later notification.
TEST_F(AdapterTest, ModellerDisabledOnNotification) {
fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
SetUpAdapter(default_params_);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
fake_modeller_.InitModellerWithCurves(base::nullopt, base::nullopt);
fake_modeller_.ReportModelInitialized();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
EXPECT_FALSE(adapter_->GetGlobalCurveForTesting());
EXPECT_FALSE(adapter_->GetPersonalCurveForTesting());
}
// Modeller is |kSuccess| on later notification.
TEST_F(AdapterTest, ModellerEnabledOnNotification) {
fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
SetUpAdapter(default_params_);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
fake_modeller_.InitModellerWithCurves(global_curve_, personal_curve_);
fake_modeller_.ReportModelInitialized();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
}
TEST_F(AdapterTest, SequenceOfBrightnessUpdatesWithDefaultParams) {
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
// Forward by 1sec because in real implementation, |first_als_time_| is zero
// if there's no ALS reading received.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
// Brightness is changed after the 1st ALS reading comes in.
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
// Another ALS value is received in 3 sec, but no brightness update is done.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(3));
fake_als_reader_.ReportAmbientLightUpdate(20);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
// |params.min_time_between_brightness_changes| has elapsed since we've made
// the change, but there's no new ALS value, hence no brightness change is
// triggered.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(10));
EXPECT_EQ(test_observer_.num_changes(), 1);
// A new ALS value triggers a brightness change.
fake_als_reader_.ReportAmbientLightUpdate(40);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 2);
// Adapter is disabled after a user manual adjustment.
fake_brightness_monitor_.ReportUserBrightnessChangeRequested();
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
// Another user manual adjustment came in.
fake_brightness_monitor_.ReportUserBrightnessChangeRequested();
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
TEST_F(AdapterTest, UserBrightnessRequestBeforeAnyModelUpdate) {
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, default_params_);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
// Adapter is disabled after a user manual adjustment.
fake_brightness_monitor_.ReportUserBrightnessChangeRequested();
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
// Another user manual adjustment came in.
fake_brightness_monitor_.ReportUserBrightnessChangeRequested();
thread_bundle_.RunUntilIdle();
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
}
TEST_F(AdapterTest, BrightnessLuxThresholds) {
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, default_params_);
EXPECT_EQ(Adapter::kNumberAmbientValuesToTrack, 5);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
// Brightness is changed after the 1st ALS value, and the thresholds are
// changed.
fake_als_reader_.ReportAmbientLightUpdate(20);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(), 20);
EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), 22);
EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), 16);
// A 2nd ALS comes in, but average ambient is within the thresholds, hence
// brightness isn't changed and thresholds aren't updated.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(20));
fake_als_reader_.ReportAmbientLightUpdate(21);
EXPECT_EQ(1, test_observer_.num_changes());
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(), (20 + 21) / 2.0);
EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), 22);
EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), 16);
// A 3rd ALS comes in, but still not enough to trigger brightness change.
fake_als_reader_.ReportAmbientLightUpdate(15);
EXPECT_EQ(test_observer_.num_changes(), 1);
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
(20 + 21 + 15) / 3.0);
EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), 22);
EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), 16);
// A 4th ALS makes average value below the darkening threshold, hence
// brightness is changed. Thresholds are also changed.
fake_als_reader_.ReportAmbientLightUpdate(7);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 2);
const double expected_average_ambient = (20 + 21 + 15 + 7) / 4.0;
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
expected_average_ambient);
EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(),
expected_average_ambient * 1.1);
EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(),
expected_average_ambient * 0.8);
// Next check |ambient_light_values_| has capacity
// |Adapter::kNumberAmbientValuesToTrack|.
fake_als_reader_.ReportAmbientLightUpdate(8);
thread_bundle_.RunUntilIdle();
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
(20 + 21 + 15 + 7 + 8) / 5.0);
fake_als_reader_.ReportAmbientLightUpdate(9);
thread_bundle_.RunUntilIdle();
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
(21 + 15 + 7 + 8 + 9) / 5.0);
}
TEST_F(AdapterTest, ImmediateBrightnessTransitionThresholds) {
std::map<std::string, std::string> params = default_params_;
params["immediate_brightening_lux_threshold_ratio"] = "0.3";
params["immediate_darkening_lux_threshold_ratio"] = "0.3";
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, params);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
// Brightness is changed after the 1st ALS reading comes in.
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
// Another ALS value is received in 1 sec, brightness is changed because it
// exceeds immediate transition threshold.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
fake_als_reader_.ReportAmbientLightUpdate(17);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 2);
// Another ALS value is received in 2 sec, brightness is changed because it
// exceeds immediate transition threshold.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(2));
fake_als_reader_.ReportAmbientLightUpdate(1);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 3);
}
TEST_F(AdapterTest, BrightnessNotUpdatedOnStartup) {
std::map<std::string, std::string> params = default_params_;
params["update_brightness_on_startup"] = "false";
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, params);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
// 1st ALS reading doesn't trigger a brightness change.
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 0);
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(5));
EXPECT_EQ(test_observer_.num_changes(), 0);
// 2nd ALS comes in so that we have |kAmbientLightShortHorizonSeconds| of
// data, hence brightness is changed.
fake_als_reader_.ReportAmbientLightUpdate(20);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
}
TEST_F(AdapterTest, UsePersonalCurve) {
std::map<std::string, std::string> params = default_params_;
params["model_curve"] = "1";
// Init modeller with only a global curve.
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, base::nullopt /* personal_curve */, params);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
// ALS comes in but no brightness change is triggered because there is no
// personal curve.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 0);
// Personal curve is received.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
fake_modeller_.ReportModelTrained(*personal_curve_);
EXPECT_EQ(test_observer_.num_changes(), 0);
fake_als_reader_.ReportAmbientLightUpdate(20);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
EXPECT_EQ(test_observer_.GetCause(),
power_manager::BacklightBrightnessChange_Cause_MODEL);
const double expected_average_ambient = (10 + 20) / 2.0;
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
expected_average_ambient);
const double expected_brightness_percent =
personal_curve_->Interpolate(ConvertToLog(expected_average_ambient));
EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
expected_brightness_percent);
}
TEST_F(AdapterTest, UseGlobalCurve) {
std::map<std::string, std::string> params = default_params_;
params["model_curve"] = "0";
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, params);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 1);
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(), 10);
const double expected_brightness_percent1 =
global_curve_->Interpolate(ConvertToLog(10));
EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
expected_brightness_percent1);
// A new personal curve is received but adapter still uses the global curve.
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(20));
fake_modeller_.ReportModelTrained(*personal_curve_);
fake_als_reader_.ReportAmbientLightUpdate(20);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 2);
EXPECT_EQ(test_observer_.GetCause(),
power_manager::BacklightBrightnessChange_Cause_MODEL);
const double expected_average_ambient2 = (10 + 20) / 2.0;
EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
expected_average_ambient2);
const double expected_brightness_percent2 =
global_curve_->Interpolate(ConvertToLog(expected_average_ambient2));
EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
expected_brightness_percent2);
}
TEST_F(AdapterTest, BrightnessSetByPolicy) {
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, default_params_,
true /* brightness_set_by_policy */);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 0);
}
TEST_F(AdapterTest, FeatureDisabled) {
// An empty param map will not enable the experiment.
std::map<std::string, std::string> empty_params;
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, empty_params);
EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
// Global and personal curves are received, but they won't be used to change
// brightness.
EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
// Brightness not changed after the 1st ALS reading comes in.
fake_als_reader_.ReportAmbientLightUpdate(10);
thread_bundle_.RunUntilIdle();
EXPECT_EQ(test_observer_.num_changes(), 0);
}
TEST_F(AdapterTest, ValidParameters) {
std::map<std::string, std::string> params = default_params_;
params["darkening_lux_threshold_ratio"] = "0.5";
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, params);
histogram_tester_.ExpectTotalCount("AutoScreenBrightness.ParameterError", 0);
}
TEST_F(AdapterTest, InvalidParameters) {
std::map<std::string, std::string> params = default_params_;
params["darkening_lux_threshold_ratio"] = "2";
Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
global_curve_, personal_curve_, params);
histogram_tester_.ExpectUniqueSample(
"AutoScreenBrightness.ParameterError",
static_cast<int>(ParameterError::kAdapterError), 1);
}
} // namespace auto_screen_brightness
} // namespace power
} // namespace chromeos