chromium/chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_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_DISPLAY_SETTINGS_DISPLAY_SETTINGS_PROVIDER_H_
#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_DEVICE_DISPLAY_SETTINGS_DISPLAY_SETTINGS_PROVIDER_H_

#include <map>

#include "ash/public/cpp/tablet_mode_observer.h"
#include "ash/shell.h"
#include "ash/shell_observer.h"
#include "ash/system/brightness_control_delegate.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/timer/timer.h"
#include "base/types/id_type.h"
#include "chrome/browser/ui/webui/ash/settings/pages/device/display_settings/display_settings_provider.mojom.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "ui/display/display.h"
#include "ui/display/display_observer.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/manager/display_manager_observer.h"

namespace ash::settings {

using DisplayId = base::IdType64<display::Display>;

// Provide information about system display settings. Implemented in the browser
// process. Called by the OS settings app.
class DisplaySettingsProvider : public mojom::DisplaySettingsProvider,
                                public TabletModeObserver,
                                public display::DisplayManagerObserver,
                                public ash::ShellObserver,
                                public display::DisplayObserver,
                                public chromeos::PowerManagerClient::Observer {
 public:
  DisplaySettingsProvider();
  ~DisplaySettingsProvider() override;
  DisplaySettingsProvider(const DisplaySettingsProvider& other) = delete;
  DisplaySettingsProvider& operator=(const DisplaySettingsProvider& other) =
      delete;

  // 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 DisplayType {
    kExternalDisplay = 0,
    kInternalDisplay = 1,
    kMaxValue = kInternalDisplay,
  };

  // Enum value for measuring display default settings performance.
  // 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 DisplayDefaultSettingsMeasurement {
    kNewDisplayConnected = 0,
    kOverrideResolution = 1,
    kOverrideScaling = 2,
    kMaxValue = kOverrideScaling,
  };

  // 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 UserInitiatedDisplayAmbientLightSensorDisabledCause {
    // The ambient light sensor was disabled directly through the settings
    // app by the user.
    kUserRequestSettingsApp = 0,
    // The ambient light sensor was disabled as a result of the user manually
    // adjusting the brightness.
    kBrightnessUserRequest = 1,
    // The ambient light sensor was disabled as a result of the user adjusting
    // the brightness through the settings app.
    kBrightnessUserRequestSettingsApp = 2,
    kMaxValue = kBrightnessUserRequestSettingsApp,
  };

  // The UMA histogram that records display settings usage.
  static constexpr char kDisplaySettingsHistogramName[] =
      "ChromeOS.Settings.Display";
  // The UMA histogram that records new display connected metrics.
  static constexpr char kNewDisplayConnectedHistogram[] =
      "ChromeOS.Settings.Display.NewDisplayConnected";

  // Records when user overrides the display resolution or scaling within an
  // hour of the display being connected for the first time.
  static constexpr char kUserOverrideInternalDisplayDefaultSettingsHistogram[] =
      "ChromeOS.Settings.Display.Internal.UserOverrideDisplayDefaultSettings";
  static constexpr char kUserOverrideExternalDisplayDefaultSettingsHistogram[] =
      "ChromeOS.Settings.Display.External.UserOverrideDisplayDefaultSettings";

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

  // mojom::DisplaySettingsProvider:
  void ObserveTabletMode(
      mojo::PendingRemote<mojom::TabletModeObserver> observer,
      ObserveTabletModeCallback callback) override;

  void ObserveDisplayConfiguration(
      mojo::PendingRemote<mojom::DisplayConfigurationObserver> observer)
      override;

  void ObserveDisplayBrightnessSettings(
      mojo::PendingRemote<mojom::DisplayBrightnessSettingsObserver> observer,
      ObserveDisplayBrightnessSettingsCallback callback) override;

  void ObserveAmbientLightSensor(
      mojo::PendingRemote<mojom::AmbientLightSensorObserver> observer,
      ObserveAmbientLightSensorCallback callback) override;

  void RecordChangingDisplaySettings(
      mojom::DisplaySettingsType type,
      mojom::DisplaySettingsValuePtr value) override;

  void SetShinyPerformance(bool enabled) override;

  void SetInternalDisplayScreenBrightness(double percent) override;

  void SetInternalDisplayAmbientLightSensorEnabled(bool enabled) override;

  void HasAmbientLightSensor(HasAmbientLightSensorCallback callback) override;

  void StartNativeTouchscreenMappingExperience() override;

  // TabletModeObserver:
  void OnTabletModeEventsBlockingChanged() override;

  // display::DisplayManagerObserver:
  void OnDidProcessDisplayChanges(
      const DisplayConfigurationChange& configuration_change) override;

  // display::DisplayObserver:
  void OnDisplayAdded(const display::Display& new_display) override;

  // PowerManagerClient::Observer:
  void ScreenBrightnessChanged(
      const power_manager::BacklightBrightnessChange& change) override;
  void AmbientLightSensorEnabledChanged(
      const power_manager::AmbientLightSensorChange& change) override;

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

  void SetBrightnessControlDelegateForTesting(
      raw_ptr<BrightnessControlDelegate> delegate) {
    brightness_control_delegate_ = delegate;
  }

 private:
  void OnGetInitialBrightness(ObserveDisplayBrightnessSettingsCallback callback,
                              std::optional<double> percent);

  void OnGetAmbientLightSensorEnabled(
      ObserveAmbientLightSensorCallback callback,
      std::optional<bool> is_ambient_light_sensor_enabled);

  void OnGetHasAmbientLightSensor(HasAmbientLightSensorCallback callback,
                                  std::optional<bool> has_ambient_light_sensor);

  void RecordBrightnessSliderAdjusted();

  base::ScopedObservation<ash::Shell, ash::ShellObserver> shell_observation_{
      this};

  // Maintain a reference to BrightnessControlDelegate so that we can test
  // behavior of methods in this class that interact with it.
  raw_ptr<BrightnessControlDelegate> brightness_control_delegate_;

  mojo::RemoteSet<mojom::TabletModeObserver> tablet_mode_observers_;

  mojo::RemoteSet<mojom::DisplayConfigurationObserver>
      display_configuration_observers_;

  mojo::RemoteSet<mojom::DisplayBrightnessSettingsObserver>
      display_brightness_settings_observers_;

  mojo::RemoteSet<mojom::AmbientLightSensorObserver>
      ambient_light_sensor_observers_;

  // A map between display id and the timestamp this display is connected. Only
  // add those displays that are connected for the first time. Used to record
  // the time elapsed between users changing the display default settings and
  // the display is connected.
  std::map<DisplayId, base::TimeTicks> displays_connection_timestamp_map_;

  // The last display brightness percentage set by the user. Used for metrics.
  double last_set_brightness_percent_;

  // Times used to prevent the brightness slider metrics from recording each
  // time the user moves the slider while setting the desired brightness.
  base::DelayTimer brightness_slider_metric_delay_timer_;

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

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

}  // namespace ash::settings

#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_PAGES_DEVICE_DISPLAY_SETTINGS_DISPLAY_SETTINGS_PROVIDER_H_