blob: 7af1e933d2469fde1284a73076d76e46de138b9f [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.
#ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/als_samples.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/model_config.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
#include "chrome/browser/profiles/profile.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/base/user_activity/user_activity_observer.h"
namespace chromeos {
namespace power {
namespace auto_screen_brightness {
// Real implementation of Modeller.
// It monitors user-requested brightness changes, ambient light values and
// trains personal brightness curves when user remains idle for a period of
// time.
// An object of this class must be used on the same thread that created this
// object.
class ModellerImpl : public Modeller,
public AlsReader::Observer,
public BrightnessMonitor::Observer,
public ModelConfigLoader::Observer,
public ui::UserActivityObserver {
public:
static constexpr char kModelDir[] = "autobrightness";
static constexpr char kCurveFileName[] = "curve";
// ModellerImpl has weak dependencies on all parameters except |trainer|.
ModellerImpl(const Profile* profile,
AlsReader* als_reader,
BrightnessMonitor* brightness_monitor,
ModelConfigLoader* model_config_loader,
ui::UserActivityDetector* user_activity_detector,
std::unique_ptr<Trainer> trainer);
~ModellerImpl() override;
// Modeller overrides:
void AddObserver(Modeller::Observer* observer) override;
void RemoveObserver(Modeller::Observer* observer) override;
// AlsReader::Observer overrides:
void OnAmbientLightUpdated(int lux) override;
void OnAlsReaderInitialized(AlsReader::AlsInitStatus status) override;
// BrightnessMonitor::Observer overrides:
void OnBrightnessMonitorInitialized(bool success) override;
void OnUserBrightnessChanged(double old_brightness_percent,
double new_brightness_percent) override;
void OnUserBrightnessChangeRequested() override;
// ModelConfigLoader::Observer overrides:
void OnModelConfigLoaded(base::Optional<ModelConfig> model_config) override;
// ui::UserActivityObserver overrides:
void OnUserActivity(const ui::Event* event) override;
// ModellerImpl has weak dependencies on all parameters except |trainer|.
static std::unique_ptr<ModellerImpl> CreateForTesting(
const Profile* profile,
AlsReader* als_reader,
BrightnessMonitor* brightness_monitor,
ModelConfigLoader* model_config_loader,
ui::UserActivityDetector* user_activity_detector,
std::unique_ptr<Trainer> trainer,
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
const base::TickClock* tick_clock);
// Current average ambient light.
base::Optional<double> AverageAmbientForTesting(base::TimeTicks now);
// Current number of training data points stored, which will be used for next
// training.
size_t NumberTrainingDataPointsForTesting() const;
// Returns |global_curve_| for unit tests.
MonotoneCubicSpline GetGlobalCurveForTesting() const;
// Returns |max_training_data_points_| for unit tests.
size_t GetMaxTrainingDataPointsForTesting() const;
base::TimeDelta GetTrainingDelayForTesting() const;
ModelConfig GetModelConfigForTesting() const;
// Returns the path that will be used to store curves. It also creates
// intermediate directories if they do not exist. Returns an empty path on
// failures.
static base::FilePath GetCurvePathFromProfile(const Profile* profile);
private:
// ModellerImpl has weak dependencies on all parameters except |trainer|.
ModellerImpl(const Profile* profile,
AlsReader* als_reader,
BrightnessMonitor* brightness_monitor,
ModelConfigLoader* model_config_loader,
ui::UserActivityDetector* user_activity_detector,
std::unique_ptr<Trainer> trainer,
scoped_refptr<base::SequencedTaskRunner> task_runner,
const base::TickClock* tick_clock,
bool is_testing = false);
// Updates |model_status_| by checking |als_init_status_| and
// |brightness_monitor_status_| and optionally loads a curve.
// 1. |model_status_| is |kDisabled| if either |als_init_status_| is not
// |kSuccess|, or |brightness_monitor_success_| is false. The modeller will
// notify its observers as soon as |model_status_| is |kDisabled|.
// 2. If |als_init_status_| is |kSuccess| and |brightness_monitor_success_| is
// true, then this method loads a curve from the disk and sets |model_status_|
// to |kPersonal|. If no curve is found from the disk a default curve will be
// created and |model_status_| is set to |kGlobal|. All observers will be
// notified about the status and the curve.
void HandleStatusUpdate();
// Load customizations from model configs.
void RunCustomization();
// Notifies its observers on the status of the model. It will be called either
// when HandleStatusUpdate is called and |model_status_| is no longer
// |kInitializing|, or when an observer is added to the modeller, and
// |model_status_| is not |kInitializing|.
void OnInitializationComplete();
// Called when the modeller is initialized. It notifies its observers about
// constructed global curve and personal curve (loaded from the disk). Both
// curves will be nullopt if model is disabled, and personal curve will be
// nullopt if no curve is loaded from the disk.
void NotifyObserverInitStatus(Modeller::Observer& observer);
// Called after we've attempted to construct a |curve| from data saved on
// disk. |curve| will be assigned to |current_curve_| if |curve| is not
// nullopt. Otherwise, |current_curve_| will have the same value as
// |global_curve_|.
void OnCurveLoadedFromDisk(const base::Optional<MonotoneCubicSpline>& curve);
void OnCurveSavedToDisk(bool is_successful);
// Called after we've set trainer's initial curves.
void OnSetInitialCurves(
const base::Optional<MonotoneCubicSpline>& loaded_curve,
bool is_personal_curve_valid);
// Either starts training immediately or delays it for |training_delay_|.
// Training starts immediately if |training_delay_| is 0 or number of training
// points reached |max_training_data_points_|.
// This function is called after a user brightness change signal is received
// (that will be used as an example), and when a user activity is detected.
// It's also called after initial curves are set.
// Nothing will happen if model is not enabled.
void ScheduleTrainerStart();
// Starts model training and runs it in non UI thread. Also clears
// |data_cache_|.
void StartTraining();
// Called after training is complete with a new curve.
void OnTrainingFinished(const MonotoneCubicSpline& curve);
// If |is_testing_| is false, we check curve saving/loading and training jobs
// are running on non-UI thread.
const bool is_testing_ = false;
// If number of recorded training data has reached |max_training_data_points_|
// we start training immediately, without waiting for user to become idle for
// |training_delay_|. This can be overridden by experiment flag
// "max_training_data_points".
size_t max_training_data_points_ = 100;
// Once user remains idle for |training_delay_|, we start training the model.
// If this value is 0, we will not need to wait for user to remain inactive.
// This can be overridden by experiment flag "training_delay_in_seconds".
base::TimeDelta training_delay_ = base::TimeDelta::FromSeconds(0);
ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_;
ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer>
brightness_monitor_observer_;
ScopedObserver<ModelConfigLoader, ModelConfigLoader::Observer>
model_config_loader_observer_;
ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver>
user_activity_observer_;
// Background task runner for IO work (loading a curve from disk and writing a
// curve to disk) and training jobs.
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
std::unique_ptr<Trainer, base::OnTaskRunnerDeleter> trainer_;
// This will be replaced by a mock tick clock during tests.
const base::TickClock* const tick_clock_;
base::OneShotTimer model_timer_;
base::Optional<AlsReader::AlsInitStatus> als_init_status_;
base::Optional<bool> brightness_monitor_success_;
// |model_config_exists_| will remain nullopt until |OnModelConfigLoaded| is
// called. Its value will then be set to true if the input model config exists
// (not nullopt), else its value will be false.
base::Optional<bool> model_config_exists_;
ModelConfig model_config_;
// Whether this modeller has initialized successfully, including connecting
// to AlsReader, BrightnessMonitor and loading a Trainer.
// Initially has no value. Guaranteed to have a value after the completion of
// |OnCurveLoadedFromDisk|.
base::Optional<bool> is_modeller_enabled_;
base::FilePath curve_path_;
// True if a personal curve was successfully loaded from disk and passed to
// Trainer and Trainer reported it was valid.
bool has_initial_personal_curve_ = false;
// Global curve constructed from predefined params. It will remain nullopt
// until |OnModelConfigLoaded| is called. If input model config is nullopt
// then |global_curve_| will remain nullopt, else it will be created based on
// the model config.
base::Optional<MonotoneCubicSpline> global_curve_;
// Current personal curve. Initially it could be either the global curve or
// loaded curve. After training, it will be updated each time trainer
// generates a new curve.
base::Optional<MonotoneCubicSpline> current_curve_;
// Recent ambient values.
std::unique_ptr<AmbientLightSampleBuffer> ambient_light_values_;
std::vector<TrainingDataPoint> data_cache_;
base::ObserverList<Modeller::Observer> observers_;
// Training start time.
base::Optional<base::TimeTicks> training_start_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<ModellerImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ModellerImpl);
};
} // namespace auto_screen_brightness
} // namespace power
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_