chromium/ash/system/unified/unified_system_tray_bubble.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_BUBBLE_H_
#define ASH_SYSTEM_UNIFIED_UNIFIED_SYSTEM_TRAY_BUBBLE_H_

#include <memory>
#include <optional>

#include "ash/public/cpp/tablet_mode_observer.h"
#include "ash/shelf/shelf_observer.h"
#include "ash/system/screen_layout_observer.h"
#include "ash/system/time/calendar_metrics.h"
#include "ash/system/tray/time_to_click_recorder.h"
#include "ash/system/tray/tray_bubble_base.h"
#include "ash/system/unified/quick_settings_view.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/widget/widget_observer.h"

namespace ui {
class Event;
}  // namespace ui

namespace views {
class Widget;
}  // namespace views

namespace ash {

class TrayEventFilter;
class UnifiedSystemTray;
class UnifiedSystemTrayController;
class QuickSettingsView;

// Manages the bubble that contains 'QuickSettingsView'.
// Shows the bubble on the constructor, and closes the bubble on the destructor.
// It is possible that the bubble widget is closed on deactivation. In such
// case, this class calls UnifiedSystemTray::CloseBubble() to delete itself.
class ASH_EXPORT UnifiedSystemTrayBubble : public TrayBubbleBase,
                                           public ScreenLayoutObserver,
                                           public ShelfObserver,
                                           public TimeToClickRecorder::Delegate,
                                           public TabletModeObserver {
 public:
  explicit UnifiedSystemTrayBubble(UnifiedSystemTray* tray);

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

  ~UnifiedSystemTrayBubble() override;

  // Add observers that can delete `this`. This needs to be done separately
  // after `UnifiedSystemTrayBubble` and `UnifiedMessageCenterBubble` have been
  // completely constructed to prevent crashes. (crbug/1310675)
  void InitializeObservers();

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

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

  // Show audio settings detailed view.
  void ShowAudioDetailedView();

  // Show display settings detailed view.
  void ShowDisplayDetailedView();

  // Show calendar view.
  void ShowCalendarView(calendar_metrics::CalendarViewShowSource show_source,
                        calendar_metrics::CalendarEventSource event_source);

  // Show network settings detailed view.
  void ShowNetworkDetailedView();

  // Update bubble bounds and focus if necessary.
  void UpdateBubble();

  // Return the current visible height of the tray, even when partially
  // collapsed / expanded.
  int GetCurrentTrayHeight() const;

  // Fire a notification that an accessibility event has occured on this object.
  void NotifyAccessibilityEvent(ax::mojom::Event event, bool send_native_event);

  // Whether the bubble is currently showing audio details or display details or
  // calendar view.
  bool ShowingAudioDetailedView() const;
  bool ShowingDisplayDetailedView() const;
  bool ShowingCalendarView() const;

  // TrayBubbleBase:
  TrayBackgroundView* GetTray() const override;
  TrayBubbleView* GetBubbleView() const override;
  views::Widget* GetBubbleWidget() const override;

  // ScreenLayoutObserver:
  void OnDidApplyDisplayChanges() override;

  // views::WidgetObserver:
  void OnWidgetDestroying(views::Widget* widget) override;

  // TimeToClickRecorder::Delegate:
  void RecordTimeToClick() override;

  // TabletModeObserver:
  void OnTabletPhysicalStateChanged() override;

  // ShelfObserver:
  void OnAutoHideStateChanged(ShelfAutoHideState new_state) override;

  // Updates the bubble height based on if it's going to show the main page or
  // the detailed page.
  void UpdateBubbleHeight(bool is_showing_detiled_view);

  QuickSettingsView* quick_settings_view() { return quick_settings_view_; }

  UnifiedSystemTrayController* unified_system_tray_controller() {
    return controller_.get();
  }

 private:
  friend class SystemTrayTestApi;

  void UpdateBubbleBounds();

  // Controller of `QuickSettingsView`. As the view is owned by views hierarchy,
  // we have to own the controller here.
  std::unique_ptr<UnifiedSystemTrayController> controller_;

  // Owner of this class.
  raw_ptr<UnifiedSystemTray> unified_system_tray_;

  // Widget that contains `QuickSettingsView`. Unowned.
  // When the widget is closed by deactivation, `bubble_widget_` pointer is
  // invalidated and we have to delete `UnifiedSystemTrayBubble` by calling
  // `UnifiedSystemTray::CloseBubble()`.
  // In order to do this, we observe `OnWidgetDestroying()`.
  raw_ptr<views::Widget> bubble_widget_ = nullptr;

  // PreTargetHandler of `quick_settings_view_` to record TimeToClick metrics.
  // Owned.
  std::unique_ptr<TimeToClickRecorder> time_to_click_recorder_;

  // The time the bubble is created.
  std::optional<base::TimeTicks> time_opened_;

  raw_ptr<TrayBubbleView> bubble_view_ = nullptr;

  raw_ptr<QuickSettingsView, DanglingUntriaged> quick_settings_view_ = nullptr;

  std::unique_ptr<TrayEventFilter> tray_event_filter_;

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

}  // namespace ash

#endif  // ASH_SYSTEM_UNIFIED_UNIFIED_SYSTEM_TRAY_BUBBLE_H_