chromium/chrome/browser/ui/webui/ash/settings/pages/device/input_device_settings/input_device_settings_provider.h

// Copyright 2023 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_DEVICE_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_SETTINGS_PROVIDER_H_
#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_DEVICE_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_SETTINGS_PROVIDER_H_

#include "ash/public/cpp/input_device_settings_controller.h"
#include "ash/public/mojom/input_device_settings.mojom.h"
#include "ash/shell.h"
#include "ash/shell_observer.h"
#include "ash/system/keyboard_brightness_control_delegate.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ui/webui/ash/settings/pages/device/input_device_settings/input_device_settings_provider.mojom.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "content/public/browser/web_ui.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"

namespace ash::settings {

// Note that these values are persisted to histograms so existing values
// should remain unchanged and new values should be added to the end.
enum class KeyboardAmbientLightSensorDisabledCause {
  // The keyboard ambient light sensor was disabled directly through the
  // settings app by the user.
  kUserRequestSettingsApp = 0,
  // The keyboard ambient light sensor was disabled as a result of the user
  // manually adjusting the brightness.
  kBrightnessUserRequest = 1,
  // The keyboard ambient light sensor was disabled as a result of the user
  // adjusting the brightness through the settings app.
  kBrightnessUserRequestSettingsApp = 2,
  kMaxValue = kBrightnessUserRequestSettingsApp,
};

class InputDeviceSettingsProvider
    : public mojom::InputDeviceSettingsProvider,
      public InputDeviceSettingsController::Observer,
      public views::WidgetObserver,
      public chromeos::PowerManagerClient::Observer,
      public ash::ShellObserver {
 public:
  InputDeviceSettingsProvider();
  InputDeviceSettingsProvider(const InputDeviceSettingsProvider& other) =
      delete;
  InputDeviceSettingsProvider& operator=(
      const InputDeviceSettingsProvider& other) = delete;
  ~InputDeviceSettingsProvider() override;

  void Initialize(content::WebUI* web_ui);

  void BindInterface(
      mojo::PendingReceiver<mojom::InputDeviceSettingsProvider> receiver);

  // mojom::InputDeviceSettingsProvider:
  void ObserveKeyboardSettings(
      mojo::PendingRemote<mojom::KeyboardSettingsObserver> observer) override;
  void ObserveTouchpadSettings(
      mojo::PendingRemote<mojom::TouchpadSettingsObserver> observer) override;
  void ObservePointingStickSettings(
      mojo::PendingRemote<mojom::PointingStickSettingsObserver> observer)
      override;
  void ObserveMouseSettings(
      mojo::PendingRemote<mojom::MouseSettingsObserver> observer) override;
  void ObserveGraphicsTabletSettings(
      mojo::PendingRemote<mojom::GraphicsTabletSettingsObserver> observer)
      override;
  void ObserveButtonPresses(
      mojo::PendingRemote<mojom::ButtonPressObserver> observer) override;
  void ObserveKeyboardBrightness(
      mojo::PendingRemote<mojom::KeyboardBrightnessObserver> observer) override;
  void ObserveKeyboardAmbientLightSensor(
      mojo::PendingRemote<mojom::KeyboardAmbientLightSensorObserver> observer)
      override;
  void ObserveLidState(mojo::PendingRemote<mojom::LidStateObserver> observer,
                       ObserveLidStateCallback callback) override;

  void RestoreDefaultKeyboardRemappings(uint32_t device_id) override;
  void SetKeyboardSettings(uint32_t device_id,
                           ::ash::mojom::KeyboardSettingsPtr settings) override;
  void SetPointingStickSettings(
      uint32_t device_id,
      ::ash::mojom::PointingStickSettingsPtr settings) override;
  void SetMouseSettings(uint32_t device_id,
                        ::ash::mojom::MouseSettingsPtr settings) override;
  void SetTouchpadSettings(uint32_t device_id,
                           ::ash::mojom::TouchpadSettingsPtr settings) override;
  void SetGraphicsTabletSettings(
      uint32_t device_id,
      ::ash::mojom::GraphicsTabletSettingsPtr settings) override;
  void SetKeyboardBrightness(double percent) override;
  void SetKeyboardAmbientLightSensorEnabled(bool enabled) override;

  // InputDeviceSettingsController::Observer:
  void OnKeyboardConnected(const ::ash::mojom::Keyboard& keyboard) override;
  void OnKeyboardDisconnected(const ::ash::mojom::Keyboard& keyboard) override;
  void OnKeyboardSettingsUpdated(
      const ::ash::mojom::Keyboard& keyboard) override;
  void OnKeyboardPoliciesUpdated(
      const ::ash::mojom::KeyboardPolicies& keyboard_policies) override;
  void OnTouchpadConnected(const ::ash::mojom::Touchpad& touchpad) override;
  void OnTouchpadDisconnected(const ::ash::mojom::Touchpad& touchpad) override;
  void OnTouchpadSettingsUpdated(
      const ::ash::mojom::Touchpad& touchpad) override;
  void OnPointingStickConnected(
      const ::ash::mojom::PointingStick& pointing_stick) override;
  void OnPointingStickDisconnected(
      const ::ash::mojom::PointingStick& pointing_stick) override;
  void OnPointingStickSettingsUpdated(
      const ::ash::mojom::PointingStick& pointing_stick) override;
  void OnMouseConnected(const ::ash::mojom::Mouse& mouse) override;
  void OnMouseDisconnected(const ::ash::mojom::Mouse& mouse) override;
  void OnMouseSettingsUpdated(const ::ash::mojom::Mouse& mouse) override;
  void OnMousePoliciesUpdated(
      const ::ash::mojom::MousePolicies& mouse_policies) override;
  void OnGraphicsTabletConnected(
      const ::ash::mojom::GraphicsTablet& graphics_tablet) override;
  void OnGraphicsTabletDisconnected(
      const ::ash::mojom::GraphicsTablet& graphics_tablet) override;
  void OnGraphicsTabletSettingsUpdated(
      const ::ash::mojom::GraphicsTablet& graphics_tablet) override;
  void OnCustomizableMouseButtonPressed(
      const ::ash::mojom::Mouse& mouse,
      const ::ash::mojom::Button& button) override;
  void OnCustomizablePenButtonPressed(
      const ::ash::mojom::GraphicsTablet& graphics_tablet,
      const ::ash::mojom::Button& button) override;
  void OnCustomizableTabletButtonPressed(
      const ::ash::mojom::GraphicsTablet& graphics_tablet,
      const ::ash::mojom::Button& button) override;
  void OnKeyboardBatteryInfoChanged(
      const ::ash::mojom::Keyboard& keyboard) override;
  void OnGraphicsTabletBatteryInfoChanged(
      const ::ash::mojom::GraphicsTablet& graphics_tablet) override;
  void OnMouseBatteryInfoChanged(const ::ash::mojom::Mouse& mouse) override;
  void OnTouchpadBatteryInfoChanged(
      const ::ash::mojom::Touchpad& touchpad) override;
  void OnMouseCompanionAppInfoChanged(
      const ::ash::mojom::Mouse& mouse) override;
  void OnKeyboardCompanionAppInfoChanged(
      const ::ash::mojom::Keyboard& keyboard) override;
  void OnTouchpadCompanionAppInfoChanged(
      const ::ash::mojom::Touchpad& touchpad) override;
  void OnGraphicsTabletCompanionAppInfoChanged(
      const ::ash::mojom::GraphicsTablet& graphics_tablet) override;

  void StartObserving(uint32_t device_id) override;
  void StopObserving() override;
  void GetActionsForMouseButtonCustomization(
      GetActionsForMouseButtonCustomizationCallback callback) override;

  void GetDeviceIconImage(const std::string& device_key,
                          GetDeviceIconImageCallback callback) override;
  void GetActionsForGraphicsTabletButtonCustomization(
      GetActionsForGraphicsTabletButtonCustomizationCallback callback) override;
  void LaunchCompanionApp(const std::string& package_id_str) override;

  // chromeos::PowerManagerClient observer:
  void KeyboardBrightnessChanged(
      const power_manager::BacklightBrightnessChange& change) override;
  void KeyboardAmbientLightSensorEnabledChanged(
      const power_manager::AmbientLightSensorChange& change) override;
  void LidEventReceived(chromeos::PowerManagerClient::LidState state,
                        base::TimeTicks time) override;
  void OnReceiveSwitchStates(
      std::optional<chromeos::PowerManagerClient::SwitchStates> switch_states);

  // ash::ShellObserver:
  void OnShellDestroying() override;

  // views::WidgetObserver:
  void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override;
  void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
  void OnWidgetDestroyed(views::Widget* widget) override;

  void SetWidgetForTesting(views::Widget* widget);
  void GetMetaKeyToDisplay(GetMetaKeyToDisplayCallback callback) override;
  void HasKeyboardBacklight(HasKeyboardBacklightCallback callback) override;
  void HasAmbientLightSensor(HasAmbientLightSensorCallback callback) override;
  void IsRgbKeyboardSupported(IsRgbKeyboardSupportedCallback callback) override;
  void RecordKeyboardColorLinkClicked() override;
  void RecordKeyboardBrightnessChangeFromSlider(double percent) override;

  void SetKeyboardBrightnessControlDelegateForTesting(
      raw_ptr<KeyboardBrightnessControlDelegate> delegate) {
    keyboard_brightness_control_delegate_ = delegate;
  }

 private:
  void NotifyKeyboardsUpdated();
  void NotifyTouchpadsUpdated();
  void NotifyPointingSticksUpdated();
  void NotifyMiceUpdated();
  void NotifyGraphicsTabletUpdated();

  void HandleObserving();

  void OnReceiveHasKeyboardBacklight(HasKeyboardBacklightCallback callback,
                                     std::optional<bool> has_backlight);

  void OnReceiveHasAmbientLightSensor(HasAmbientLightSensorCallback callback,
                                      std::optional<bool> has_sensor);

  void OnReceiveKeyboardBrightness(std::optional<double> brightness_percent);

  void OnReceiveKeyboardAmbientLightSensorEnabled(
      std::optional<bool> keyboard_ambient_light_sensor_enabled);

  void OnReceiveDeviceImage(GetDeviceIconImageCallback callback,
                            const std::optional<std::string>& data_url);

  // Denotes whether button observing should be paused due to the settings app
  // being out of focus or minimized. Default to true to require a valid widget
  // to observe devices.
  bool observing_paused_ = true;

  // Whether the laptop lid is closed or open. On chromeboxes, this will always
  // be false.
  bool is_lid_open_ = false;

  // The list of device ids to observe when the settings app is focused or in
  // use by the user.
  base::flat_set<uint32_t> observing_devices_;

  mojo::RemoteSet<mojom::KeyboardSettingsObserver> keyboard_settings_observers_;
  mojo::RemoteSet<mojom::TouchpadSettingsObserver> touchpad_settings_observers_;
  mojo::RemoteSet<mojom::PointingStickSettingsObserver>
      pointing_stick_settings_observers_;
  mojo::RemoteSet<mojom::MouseSettingsObserver> mouse_settings_observers_;
  mojo::RemoteSet<mojom::GraphicsTabletSettingsObserver>
      graphics_tablet_settings_observers_;
  mojo::RemoteSet<mojom::ButtonPressObserver> button_press_observers_;
  mojo::Remote<mojom::KeyboardBrightnessObserver> keyboard_brightness_observer_;
  mojo::Remote<mojom::KeyboardAmbientLightSensorObserver>
      keyboard_ambient_light_sensor_observer_;
  mojo::RemoteSet<mojom::LidStateObserver> lid_state_observers_;

  raw_ptr<views::Widget> widget_ = nullptr;

  raw_ptr<KeyboardBrightnessControlDelegate>
      keyboard_brightness_control_delegate_ = nullptr;

  mojo::Receiver<mojom::InputDeviceSettingsProvider> receiver_{this};

  // The observation on `ash::Shell`.
  base::ScopedObservation<ash::Shell, ash::ShellObserver> shell_observation_{
      this};

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

}  // namespace ash::settings

#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_DEVICE_INPUT_DEVICE_SETTINGS_INPUT_DEVICE_SETTINGS_PROVIDER_H_