chromium/ash/system/night_light/night_light_controller_impl.h

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_CONTROLLER_IMPL_H_
#define ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_CONTROLLER_IMPL_H_

#include <memory>

#include "ash/ash_export.h"
#include "ash/public/cpp/night_light_controller.h"
#include "ash/public/cpp/schedule_enums.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/system/night_light/night_light_metrics_recorder.h"
#include "ash/system/scheduled_feature/scheduled_feature.h"
#include "ash/system/time/time_of_day.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "ui/aura/env_observer.h"
#include "ui/display/manager/display_manager_observer.h"
#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/message_center/public/cpp/notification_delegate.h"

class PrefRegistrySimple;

namespace message_center {
class Notification;
}  // namespace message_center

namespace ash {

class ColorTemperatureAnimation;

// Controls the NightLight feature that adjusts the color temperature of the
// screen. It uses the display's hardware CRTC (Cathode Ray Tube Controller)
// color transform matrix (CTM) when possible for efficiency, and can fall back
// to setting a color matrix on the compositor if the display doesn't support
// color transformation.
// For Unified Desktop mode, the color matrix is set on the mirroring actual
// displays' hosts, rather than on the Unified host, so that we can use the
// CRTC matrix if available (the Unified host doesn't correspond to an actual
// display).
class ASH_EXPORT NightLightControllerImpl
    : public NightLightController,
      public display::DisplayManagerObserver,
      public aura::EnvObserver,
      public message_center::NotificationObserver,
      public ScheduledFeature {
 public:
  enum class AnimationDuration {
    // Short animation (2 seconds) used for manual changes of NightLight status
    // and temperature by the user.
    kShort,

    // Long animation (20 seconds) used for applying the color temperature
    // gradually as a result of getting into or out of the automatically
    // scheduled NightLight mode. This gives the user a smooth transition.
    kLong,
  };

  NightLightControllerImpl();

  NightLightControllerImpl(const NightLightControllerImpl&) = delete;
  NightLightControllerImpl& operator=(const NightLightControllerImpl&) = delete;

  ~NightLightControllerImpl() override;

  static void RegisterProfilePrefs(PrefRegistrySimple* registry);

  // Convenience functions for converting between the color temperature value,
  // and the blue and green color scales. Note that the red color scale remains
  // unaffected (i.e. its scale remains 1.0f);
  static float BlueColorScaleFromTemperature(float temperature);
  static float GreenColorScaleFromTemperature(float temperature);

  // When reading ambient color temperature via powerd, it needs to be mapped
  // to another temperature before it can be used to determine the RGB scale
  // factors (i.e: CTM diagonal).  The mapping was computed according to
  // internal user studies.
  // The returned adjusted temperature is in Kelvin as well.
  static float RemapAmbientColorTemperature(float temperature_in_kelvin);

  // Given an overall temperature in Kelvin, returns the scale factors for R, G
  // and B channel.
  // |temperature_in_kelvin| is expected to be a remapped color temperature
  // from the sensor using |RemapAmbientColorTemperature|.
  static gfx::Vector3dF ColorScalesFromRemappedTemperatureInKevin(
      float temperature_in_kelvin);

  AnimationDuration animation_duration() const { return animation_duration_; }
  AnimationDuration last_animation_duration() const {
    return last_animation_duration_;
  }
  float ambient_temperature() const { return ambient_temperature_; }
  const gfx::Vector3dF& ambient_rgb_scaling_factors() const {
    return ambient_rgb_scaling_factors_;
  }

  float GetColorTemperature() const;
  bool GetAmbientColorEnabled() const;

  // Update |ambient_rgb_scaling_factors_| from the current
  // |ambient_temperature_|.
  void UpdateAmbientRgbScalingFactors();

  // Set the desired NightLight settings in the current active user prefs.
  void SetColorTemperature(float temperature);
  void SetAmbientColorEnabled(bool enabled);

  // This is always called as a result of a user action and will always use the
  // AnimationDurationType::kShort.
  void Toggle();

  // ui::display::DisplayManagerObserver:
  void OnDidApplyDisplayChanges() override;

  // aura::EnvObserver:
  void OnHostInitialized(aura::WindowTreeHost* host) override;

  // ash::NightLightController:
  bool IsNightLightEnabled() const override;

  // chromeos::PowerManagerClient::Observer:
  void AmbientColorChanged(const int32_t color_temperature) override;

  // message_center::NotificationObserver:
  void Close(bool by_user) override;
  void Click(const std::optional<int>& button_index,
             const std::optional<std::u16string>& reply) override;

  // Returns the Auto Night Light notification if any is currently shown, or
  // nullptr.
  message_center::Notification* GetAutoNightLightNotificationForTesting() const;

 private:
  // ScheduledFeature:
  void RefreshFeatureState(RefreshReason reason) override;
  const char* GetFeatureName() const override;
  void InitFeatureForNewActiveUser() override;
  void ListenForPrefChanges(
      PrefChangeRegistrar& pref_change_registrar) override;
  const char* GetScheduleTypeHistogramName() const override;

  // Returns true if the user has ever changed the schedule type, which means we
  // must respect the user's choice and let it overwrite Auto Night Light.
  bool UserHasEverChangedSchedule() const;

  // Returns true if the user has ever dismissed the Auto Night Light
  // notification, in which case we never show it again.
  bool UserHasEverDismissedAutoNightLightNotification() const;

  // Shows the notification informing the user that Night Light has been turned
  // on from sunset-to-sunrise as a result of Auto Night Light.
  void ShowAutoNightLightNotification();

  // Disables showing the Auto Night Light from now on.
  void DisableShowingFutureAutoNightLightNotification();

  // Refreshes the displays color transforms based on the given
  // |color_temperature|, which will be overridden to a value of 0 if NightLight
  // is turned off.
  void RefreshDisplaysTemperature(float color_temperature);

  // Reapplys the current color temperature on the displays without starting a
  // new animation or overriding an on-going one towards the same target
  // temperature.
  void ReapplyColorTemperatures();

  void NotifyStatusChanged();

  void NotifyClientWithScheduleChange();

  // Called when the user pref for the enabled status of Ambient Color is
  // changed.
  void OnAmbientColorEnabledPrefChanged();

  // Called when the user pref for the color temperature is changed.
  void OnColorTemperaturePrefChanged();

  void UpdateAutoNightLightNotification(RefreshReason refresh_reason);

  // The animation duration of any upcoming future change.
  AnimationDuration animation_duration_ = AnimationDuration::kShort;
  // The animation duration of the change that was just performed.
  AnimationDuration last_animation_duration_ = AnimationDuration::kShort;

  std::unique_ptr<ColorTemperatureAnimation> temperature_animation_;

  std::unique_ptr<NightLightMetricsRecorder> night_light_metrics_recorder_;

  // True only until Night Light is initialized from the very first user
  // session. After that, it is set to false.
  bool is_first_user_init_ = true;

  // Last ambient temperature read from the sensor. It is continuously
  // updated for every new value even when GetAmbientColorEnabled() returns
  // false.
  float ambient_temperature_;

  // The ambient color R, G, and B scaling factors.
  // Valid only if ambient color is enabled.
  gfx::Vector3dF ambient_rgb_scaling_factors_ = {1.f, 1.f, 1.f};

  // Night light state in the last call to `RefreshFeatureState()`. `nullopt`
  // if no call has been made yet.
  std::optional<bool> last_observed_enabled_state_;

  base::WeakPtrFactory<NightLightControllerImpl> weak_ptr_factory_;
};

}  // namespace ash

#endif  // ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_CONTROLLER_IMPL_H_