chromium/ash/system/unified/unified_system_tray.h

// Copyright 2018 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_UNIFIED_UNIFIED_SYSTEM_TRAY_H_
#define ASH_SYSTEM_UNIFIED_UNIFIED_SYSTEM_TRAY_H_

#include <list>
#include <memory>
#include <string>

#include "ash/ash_export.h"
#include "ash/public/cpp/shelf_config.h"
#include "ash/public/cpp/tablet_mode_observer.h"
#include "ash/system/power/tray_power.h"
#include "ash/system/tray/tray_background_view.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "ash/system/unified/unified_system_tray_model.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/display/display_observer.h"

namespace display {
enum class TabletState;
}  // namespace display

namespace ui {
class Event;
}  // namespace ui

namespace views {
class Widget;
}  // namespace views

namespace ash {

class AutozoomToastController;
class CameraMicTrayItemView;
class ChannelIndicatorView;
class CurrentLocaleView;
class HotspotTrayView;
class ImeModeView;
class ManagedDeviceTrayItemView;
class NetworkTrayView;
class PrivacyScreenToastController;
class Shelf;
class TrayBubbleView;
class TrayItemView;
class TimeTrayItemView;
class UnifiedSliderBubbleController;
class UnifiedSliderView;
class UnifiedSystemTrayBubble;

// The UnifiedSystemTray is the system menu of Chromium OS, which is a clickable
// rounded rectangle typically located on the bottom right corner of the screen,
// (called the Status Area). The system tray shows multiple icons on it to
// indicate system status (e.g. time, power, etc.).
//
// Note that the Status Area refers to the parent container of the
// UnifiedSystemTray, which also includes other "trays" such as the ImeMenuTray,
// SelectToSpeakTray, VirtualKeyboardTray, etc.
//
// UnifiedSystemTrayBubble is the actual menu bubble shown above the system tray
// after the user clicks on it. The UnifiedSystemTrayBubble is created and owned
// by this class.
class ASH_EXPORT UnifiedSystemTray
    : public TrayBackgroundView,
      public ShelfConfig::Observer,
      public UnifiedSystemTrayController::Observer,
      public display::DisplayObserver {
  METADATA_HEADER(UnifiedSystemTray, TrayBackgroundView)

 public:
  class Observer : public base::CheckedObserver {
   public:
    // Gets called when showing calendar view.
    virtual void OnOpeningCalendarView() {}

    // Gets called when leaving from the calendar view.
    virtual void OnLeavingCalendarView() {}

    // Gets called when a slider bubble is shown or closed.
    virtual void OnSliderBubbleHeightChanged() {}
  };

  explicit UnifiedSystemTray(Shelf* shelf);

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

  ~UnifiedSystemTray() override;

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // Callback called when this is pressed.
  void OnButtonPressed(const ui::Event& event);

  // True if the bubble is shown. It does not include slider bubbles, and when
  // they're shown it still returns false.
  bool IsBubbleShown() const;

  // True if a slider bubble e.g. volume slider triggered by keyboard
  // accelerator is shown.
  bool IsSliderBubbleShown() const;

  // Gets the slider view of the slider bubble.
  UnifiedSliderView* GetSliderView() const;

  // True if the bubble is active.
  bool IsBubbleActive() const;

  // Closes all secondary bubbles (e.g. volume/brightness sliders, autozoom,
  // privacy screen toast) if any are shown.
  // TODO(b/279044049): Consider making autozoom and privacy screen slider
  // bubbles, or have them extend a common class with sliders.
  void CloseSecondaryBubbles();

  // Activates the system tray bubble.
  void ActivateBubble();

  // Shows volume slider bubble shown at the right bottom of screen. The bubble
  // is same as one shown when volume buttons on keyboard are pressed.
  void ShowVolumeSliderBubble();

  // Shows main bubble with audio settings detailed view.
  void ShowAudioDetailedViewBubble();

  // Shows main bubble with display settings detailed view.
  void ShowDisplayDetailedViewBubble();

  // Shows main bubble with network settings detailed view.
  void ShowNetworkDetailedViewBubble();

  // Return the bounds of the bubble in the screen.
  gfx::Rect GetBubbleBoundsInScreen() const;

  // Enable / disable UnifiedSystemTray button in status area. If the bubble is
  // open when disabling, also close it.
  void SetTrayEnabled(bool enabled);

  // Notifies the height of the secondary bubble (e.g. Volume/Brightness
  // sliders, Privacy screen/Autozoom toast) if one is showing so notification
  // popups or toasts won't overlap with it. Pass 0 if no bubble is shown.
  void NotifySecondaryBubbleHeight(int height);

  // Called by `UnifiedSystemTrayBubble` when it is destroyed with the calendar
  // view in the foreground.
  void NotifyLeavingCalendarView();

  // This enum is for the ChromeOS.SystemTray.FirstInteraction UMA histogram and
  // should be kept in sync.
  enum class FirstInteractionType {
    kQuickSettings = 0,
    kMessageCenter = 1,
    kMaxValue = kMessageCenter,
  };

  // Records a metric of the first interaction with the tray bubble, i.e.
  // whether it was a click/tap on the message center or quick settings.
  void MaybeRecordFirstInteraction(FirstInteractionType type);

  // TrayBackgroundView:
  void ShowBubble() override;
  void CloseBubbleInternal() override;
  std::u16string GetAccessibleNameForBubble() override;
  std::u16string GetAccessibleNameForTray() override;
  void HandleLocaleChange() override;
  void HideBubble(const TrayBubbleView* bubble_view) override;
  void HideBubbleWithView(const TrayBubbleView* bubble_view) override;
  void ClickedOutsideBubble(const ui::LocatedEvent& event) override;
  void UpdateTrayItemColor(bool is_active) override;
  void UpdateLayout() override;
  void UpdateAfterLoginStatusChange() override;
  bool ShouldEnableExtraKeyboardAccessibility() override;
  views::Widget* GetBubbleWidget() const override;
  TrayBubbleView* GetBubbleView() override;
  std::optional<AcceleratorAction> GetAcceleratorAction() const override;

  // ShelfConfig::Observer:
  void OnShelfConfigUpdated() override;

  // UnifiedSystemTrayController::Observer:
  void OnOpeningCalendarView() override;
  void OnTransitioningFromCalendarToMainView() override;

  // display::DisplayObserver:
  void OnDisplayTabletStateChanged(display::TabletState state) override;

  // Gets called when an action is performed on the `DateTray`.
  void OnDateTrayActionPerformed(const ui::Event& event);

  // Whether the bubble is currently showing the calendar view.
  bool IsShowingCalendarView() const;

  // Returns whether the channel indicator should be shown.
  bool ShouldChannelIndicatorBeShown() const;

  std::u16string GetAccessibleNameForQuickSettingsBubble();

  scoped_refptr<UnifiedSystemTrayModel> model() { return model_; }
  UnifiedSystemTrayBubble* bubble() { return bubble_.get(); }

  ChannelIndicatorView* channel_indicator_view() {
    return channel_indicator_view_;
  }

  UnifiedSliderBubbleController* slider_bubble_controller() {
    return slider_bubble_controller_.get();
  }

  CameraMicTrayItemView* mic_view() { return mic_view_; }

 private:
  friend class NotificationGroupingControllerTest;
  friend class SystemTrayTestApi;
  friend class UnifiedSystemTrayTest;
  friend class PowerTrayViewTest;
  friend class StatusAreaBatteryPixelTest;

  // Forwarded from `UiDelegate`.
  void ShowBubbleInternal();
  void HideBubbleInternal();

  // Adds the tray item to the the unified system tray container. An unowned
  // pointer is stored in `tray_items_`.
  template <typename T>
  T* AddTrayItemToContainer(std::unique_ptr<T> tray_item_view);

  // Destroys the `bubble_`, also handles
  // removing bubble related observers.
  void DestroyBubble();

  std::unique_ptr<UnifiedSystemTrayBubble> bubble_;

  // Model class that stores `UnifiedSystemTray`'s UI specific variables.
  scoped_refptr<UnifiedSystemTrayModel> model_;

  const std::unique_ptr<UnifiedSliderBubbleController>
      slider_bubble_controller_;

  const std::unique_ptr<PrivacyScreenToastController>
      privacy_screen_toast_controller_;

  std::unique_ptr<AutozoomToastController> autozoom_toast_controller_;

  // Owned by the views hierarchy.
  raw_ptr<CurrentLocaleView> current_locale_view_ = nullptr;
  raw_ptr<ImeModeView> ime_mode_view_ = nullptr;
  raw_ptr<ManagedDeviceTrayItemView> managed_device_view_ = nullptr;
  raw_ptr<CameraMicTrayItemView> camera_view_ = nullptr;
  raw_ptr<CameraMicTrayItemView> mic_view_ = nullptr;
  raw_ptr<TimeTrayItemView> time_view_ = nullptr;
  raw_ptr<HotspotTrayView> hotspot_tray_view_ = nullptr;
  raw_ptr<NetworkTrayView> network_tray_view_ = nullptr;
  raw_ptr<ChannelIndicatorView> channel_indicator_view_ = nullptr;
  raw_ptr<PowerTrayView> power_tray_view_ = nullptr;

  // Contains all tray items views added to tray_container().
  std::list<raw_ptr<TrayItemView, CtnExperimental>> tray_items_;

  bool first_interaction_recorded_ = false;

  base::ObserverList<Observer> observers_;

  display::ScopedDisplayObserver display_observer_{this};

  // Records time the QS bubble was shown. Used for metrics.
  base::TimeTicks time_opened_;

  base::WeakPtrFactory<UnifiedSystemTray> weak_factory_{this};
};

}  // namespace ash

#endif  // ASH_SYSTEM_UNIFIED_UNIFIED_SYSTEM_TRAY_H_