chromium/chrome/browser/ui/webui/ash/settings/pages/power/device_power_handler.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 CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_POWER_DEVICE_POWER_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_POWER_DEVICE_POWER_HANDLER_H_

#include <memory>
#include <optional>
#include <set>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power/power_policy_controller.h"

class PrefChangeRegistrar;
class PrefService;

namespace base {
class TimeTicks;
}  // namespace base

namespace ash::settings {

// Chrome OS battery status and power settings handler.
class PowerHandler : public ::settings::SettingsPageUIHandler,
                     public chromeos::PowerManagerClient::Observer {
 public:
  // Idle behaviors presented in the UI. These are mapped to preferences by
  // HandleSetIdleBehavior(). Values are shared with JS and exposed here for
  // tests.
  enum class IdleBehavior {
    DISPLAY_OFF_SLEEP = 0,
    DISPLAY_OFF = 1,
    DISPLAY_ON = 2,
    SHUT_DOWN = 3,
    STOP_SESSION = 4,
  };

  // WebUI message name and dictionary keys. Shared with tests.
  static const char kPowerManagementSettingsChangedName[];
  static const char kPossibleAcIdleBehaviorsKey[];
  static const char kPossibleBatteryIdleBehaviorsKey[];
  static const char kAcIdleManagedKey[];
  static const char kBatteryIdleManagedKey[];
  static const char kCurrentAcIdleBehaviorKey[];
  static const char kCurrentBatteryIdleBehaviorKey[];
  static const char kLidClosedBehaviorKey[];
  static const char kLidClosedControlledKey[];
  static const char kHasLidKey[];
  static const char kAdaptiveChargingKey[];
  static const char kAdaptiveChargingManagedKey[];
  static const char kBatterySaverFeatureEnabledKey[];

  // Class used by tests to interact with PowerHandler internals.
  class TestAPI {
   public:
    explicit TestAPI(PowerHandler* handler);

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

    ~TestAPI();

    void RequestPowerManagementSettings();
    // Sets AC idle behavior to |behavior| if |when_on_ac| is true. Otherwise
    // sets battery idle behavior to |behavior|.
    void SetIdleBehavior(IdleBehavior behavior, bool when_on_ac);
    void SetLidClosedBehavior(chromeos::PowerPolicyController::Action behavior);
    void SetAdaptiveCharging(bool enabled);

   private:
    raw_ptr<PowerHandler> handler_;  // Not owned.
  };

  explicit PowerHandler(PrefService* prefs);

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

  ~PowerHandler() override;

  // SettingsPageUIHandler implementation.
  void RegisterMessages() override;
  void OnJavascriptAllowed() override;
  void OnJavascriptDisallowed() override;

  // chromeos::PowerManagerClient implementation.
  void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
  void PowerManagerRestarted() override;
  void LidEventReceived(chromeos::PowerManagerClient::LidState state,
                        base::TimeTicks timestamp) override;

 private:
  enum class PowerSource { kAc, kBattery };

  // Struct holding possible idle behaviors and the current behavior while
  // charging/when on battery.
  struct IdleBehaviorInfo {
    IdleBehaviorInfo();
    IdleBehaviorInfo(const std::set<IdleBehavior>& possible_behaviors,
                     const IdleBehavior& current_behavior,
                     const bool is_managed);

    IdleBehaviorInfo(const IdleBehaviorInfo& o);
    ~IdleBehaviorInfo();

    bool operator==(const IdleBehaviorInfo& o) const {
      return (possible_behaviors == o.possible_behaviors &&
              current_behavior == o.current_behavior &&
              is_managed == o.is_managed);
    }

    // All possible idle behaviors.
    std::set<IdleBehavior> possible_behaviors;
    // Current idle behavior.
    IdleBehavior current_behavior = IdleBehavior::DISPLAY_OFF_SLEEP;
    // Whether enterpise policy manages idle behavior.
    bool is_managed = false;
  };

  // Handler to request updating the power status.
  void HandleUpdatePowerStatus(const base::Value::List& args);

  // Handler to change the power source.
  void HandleSetPowerSource(const base::Value::List& args);

  // Handler to request the current power management settings. Just calls
  // SendPowerManagementSettings().
  void HandleRequestPowerManagementSettings(const base::Value::List& args);

  // Handlers to change the idle and lid-closed behaviors.
  void HandleSetIdleBehavior(const base::Value::List& args);
  void HandleSetLidClosedBehavior(const base::Value::List& args);

  // Handler to toggle adaptive charging behavior.
  void HandleSetAdaptiveCharging(const base::Value::List& args);

  // Updates the UI with the current battery status.
  void SendBatteryStatus();

  // Updates the UI with a list of available dual-role power sources.
  void SendPowerSources();

  // Updates the UI to display the current power management settings. If the
  // settings didn't change since the previous call, nothing is sent unless
  // |force| is true.
  void SendPowerManagementSettings(bool force);

  // Callback used to receive switch states from PowerManagerClient.
  void OnGotSwitchStates(
      std::optional<chromeos::PowerManagerClient::SwitchStates> result);

  // Returns all possible idle behaviors (that a user can choose from) and
  // current idle behavior based on enterprise policy and other factors when on
  // |power_source|.
  IdleBehaviorInfo GetAllowedIdleBehaviors(PowerSource power_source);

  // Returns true if the enterprise policy enforces any settings that can impact
  // the idle behavior of the device when on |power_source|.
  bool IsIdleManaged(PowerSource power_source);

  const raw_ptr<PrefService> prefs_;

  // Used to watch power management prefs for changes so the UI can be notified.
  std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;

  base::ScopedObservation<chromeos::PowerManagerClient,
                          chromeos::PowerManagerClient::Observer>
      power_manager_client_observation_{this};

  // Last lid state received from powerd.
  chromeos::PowerManagerClient::LidState lid_state_ =
      chromeos::PowerManagerClient::LidState::OPEN;

  // Last values sent by SendPowerManagementSettings(), cached here so
  // SendPowerManagementSettings() can avoid spamming the UI after this class
  // changes multiple prefs at once.
  IdleBehaviorInfo last_ac_idle_info_;
  IdleBehaviorInfo last_battery_idle_info_;
  chromeos::PowerPolicyController::Action last_lid_closed_behavior_ =
      chromeos::PowerPolicyController::ACTION_SUSPEND;
  bool last_lid_closed_controlled_ = false;
  bool last_has_lid_ = true;
  bool last_adaptive_charging_ = false;
  bool last_adaptive_charging_managed_ = false;
  bool last_battery_saver_feature_enabled_ = false;

  base::WeakPtrFactory<PowerHandler> weak_ptr_factory_{this};
};

}  // namespace ash::settings

#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_POWER_DEVICE_POWER_HANDLER_H_