chromium/ash/wm/overview/overview_grid.h

// Copyright 2014 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_WM_OVERVIEW_OVERVIEW_GRID_H_
#define ASH_WM_OVERVIEW_OVERVIEW_GRID_H_

#include <memory>
#include <vector>

#include "ash/public/cpp/desk_template.h"
#include "ash/public/cpp/wallpaper/wallpaper_controller_observer.h"
#include "ash/rotator/screen_rotation_animator_observer.h"
#include "ash/wm/desks/desk_bar_view_base.h"
#include "ash/wm/desks/templates/saved_desk_util.h"
#include "ash/wm/overview/birch/birch_bar_view.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_item.h"
#include "ash/wm/overview/overview_observer.h"
#include "ash/wm/overview/overview_types.h"
#include "ash/wm/splitview/split_view_drag_indicators.h"
#include "ash/wm/splitview/split_view_observer.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"

namespace aura {
class Window;
}  // namespace aura

namespace gfx {
class Rect;
class RectF;
}  // namespace gfx

namespace views {
class Widget;
}  // namespace views

namespace ui {
class PresentationTimeRecorder;
}  // namespace ui

namespace ash {

class OverviewDeskBarView;
class OverviewDropTarget;
class OverviewGridEventHandler;
class OverviewItemBase;
class OverviewSession;
class RoundedLabelWidget;
class SavedDeskSaveDeskButton;
class SavedDeskSaveDeskButtonContainer;
class SavedDeskLibraryView;
class ScopedOverviewHideWindows;
class ScopedOverviewWallpaperClipper;
class SplitViewController;
class SplitViewSetupView;
class WindowOcclusionCalculator;

// An instance of this class is created during the initialization of an overview
// session which manages and positions the overview UI on a per root window
// basis. Overview UI elements include:
//   - Desks bar view which contains a desk preview and desk name per desk.
//   - Splitview indicators for snapping windows in overview.
//   - Overview items representing each application window associated with the
//     root window of the grid.
//   - Saved desk UI elements to create saved desks and display saved desks.
//   - etc.
class ASH_EXPORT OverviewGrid : public SplitViewObserver,
                                public ScreenRotationAnimatorObserver,
                                public WallpaperControllerObserver,
                                public OverviewItem::WindowDestructionDelegate {
 public:
  class MetricsTracker {
   public:
    MetricsTracker() = default;
    virtual ~MetricsTracker() = default;
  };

  OverviewGrid(
      aura::Window* root_window,
      const std::vector<raw_ptr<aura::Window, VectorExperimental>>& window_list,
      OverviewSession* overview_session,
      base::WeakPtr<WindowOcclusionCalculator> window_occlusion_calculator);

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

  ~OverviewGrid() override;

  const gfx::Rect& bounds() const { return bounds_; }

  // Exits overview mode.
  void Shutdown(OverviewEnterExitType exit_type);

  // Prepares the windows in this grid for overview. This will restore all
  // minimized windows and ensure they are visible.
  void PrepareForOverview();

  // Positions all the windows in rows of equal height scaling each window to
  // fit that height. Optionally animates the windows to their targets when
  // |animate| is true. Items in |ignored_items| are not positioned. This is for
  // dragging. |transition| specifies the overview state when this function is
  // called. Updates the save desk template button if necessary.
  void PositionWindows(
      bool animate,
      const base::flat_set<OverviewItemBase*>& ignored_items = {},
      OverviewTransition transition = OverviewTransition::kInOverview);

  // Used when feature ContinuousOverviewScrollAnimation is enabled. Positions
  // the windows according to the y_offset. Uses the same logic as
  // `PositionWindows()` to determine the final state of each window. Minimized
  // windows, and the save desk button, fade in accordingly based on the scroll
  // offset.
  void PositionWindowsContinuously(float y_offset);

  // Returns the `OverviewItemBase` if a window is contained in any of the
  // OverviewItems this grid owns. Returns nullptr if no such a OverviewItem
  // exist.
  OverviewItemBase* GetOverviewItemContaining(const aura::Window* window) const;

  // Adds |window| at the specified |index|. |window| cannot already be on the
  // grid. If |reposition| is true, repositions all items except those in
  // |ignored_items|. If |animate| is true, animates the repositioning.
  // |animate| has no effect if |reposition| is false.
  // If |use_spawn_animation| is true, and this item is being added *while*
  // overview is already active, it will use a special spawn animation on its
  // first position in the grid. |use_spawn_animation| has no effect if either
  // |animate| or |reposition| are false.
  // If |reposition|, |animate|, and |restack| are all true, the stacking order
  // will be adjusted after the animation. If |restack| is true but at least one
  // of |reposition| and |animate| is false, the stacking order will be adjusted
  // immediately.
  // Note: OverviewSession has versions of the Add/Remove items. Those are
  // preferred as they will call into these functions and update other things
  // like the overview accessibility annotator and the no recent items widget.
  void AddItem(aura::Window* window,
               bool reposition,
               bool animate,
               const base::flat_set<OverviewItemBase*>& ignored_items,
               size_t index,
               bool use_spawn_animation,
               bool restack);

  // Similar to the above function, but adds the window to the end of the grid.
  void AppendItem(aura::Window* window,
                  bool reposition,
                  bool animate,
                  bool use_spawn_animation);

  // Like |AddItem|, but adds |window| at the correct position according to MRU
  // order.
  void AddItemInMruOrder(aura::Window* window,
                         bool reposition,
                         bool animate,
                         bool restack,
                         bool use_spawn_animation);

  // Removes |overview_item| from the grid. |overview_item| cannot already be
  // absent from the grid. If |item_destroying| is true, we may want to notify
  // |overview_session_| that this grid has become empty. If |item_destroying|
  // and |reposition| are both true, all items are repositioned with animation.
  // |reposition| has no effect if |item_destroying| is false.
  void RemoveItem(OverviewItemBase* overview_item,
                  bool item_destroying,
                  bool reposition);

  // Removes all overview items and restores the respective windows. This is
  // used when launching a saved desk. While this will empty the grid, it will
  // *not* invoke `OverviewSession::OnGridEmpty()` since the grid is about to
  // get filled with new windows.
  void RemoveAllItemsForSavedDeskLaunch();

  // Adds a drop target for |dragged_item|, at the index immediately following
  // |dragged_item|. Repositions all items except |dragged_item|, so that the
  // drop target takes the place of |dragged_item|. Does not animate the
  // repositioning or fade in the drop target. The visual effect is that the
  // drop target was already present but was covered by |dragged_item|.
  void AddDropTargetForDraggingFromThisGrid(OverviewItemBase* dragged_item);

  // Adds a drop target for |dragged_window|. Used for dragging from another
  // grid, from the top in tablet mode, or from the shelf in tablet mode.
  void AddDropTargetNotForDraggingFromThisGrid(aura::Window* dragged_window,
                                               bool animate);

  // Removes the drop target from the grid.
  void RemoveDropTarget();

  // Sets bounds for the window grid and positions all windows in the grid,
  // except windows in |ignored_items|.
  void SetBoundsAndUpdatePositions(
      const gfx::Rect& bounds_in_screen,
      const base::flat_set<OverviewItemBase*>& ignored_items,
      bool animate);

  // Updates overview bounds and hides the drop target when a preview area is
  // shown or the drag is currently outside of |root_window_|. For dragging from
  // the top or from the shelf, pass null for |dragged_item|.
  void RearrangeDuringDrag(
      OverviewItemBase* dragged_item,
      SplitViewDragIndicators::WindowDraggingState window_dragging_state);

  // Sets the dragged window on |split_view_drag_indicators_|.
  void SetSplitViewDragIndicatorsDraggedWindow(aura::Window* dragged_window);

  // Sets the window dragging state on |split_view_drag_indicators_|.
  void SetSplitViewDragIndicatorsWindowDraggingState(
      SplitViewDragIndicators::WindowDraggingState window_dragging_state);

  // Updates the desks bar widget bounds if necessary.
  // Returns true if the desks widget's bounds have been updated.
  bool MaybeUpdateDesksWidgetBounds();

  // Updates the birch bar widget bounds if necessary.
  // Returns true if the birch bar widget's bounds have been updated.
  bool MaybeUpdateBirchBarWidgetBounds();

  // Updates the appearance of the drop target to visually indicate when the
  // dragged window is being dragged over it. For dragging from the top or from
  // the shelf, pass null for |dragged_item|.
  void UpdateDropTargetBackgroundVisibility(
      OverviewItemBase* dragged_item,
      const gfx::PointF& location_in_screen);

  // Called when any OverviewItem on any OverviewGrid has started/ended being
  // dragged.
  void OnOverviewItemDragStarted();
  void OnOverviewItemDragEnded(bool snap);

  // Called when a window (either it's browser window or an app window)
  // start/continue/end being dragged in tablet mode.
  void OnWindowDragStarted(aura::Window* dragged_window, bool animate);
  void OnWindowDragContinued(
      aura::Window* dragged_window,
      const gfx::PointF& location_in_screen,
      SplitViewDragIndicators::WindowDraggingState window_dragging_state);
  void OnWindowDragEnded(aura::Window* dragged_window,
                         const gfx::PointF& location_in_screen,
                         bool should_drop_window_into_overview,
                         bool snap);

  // Called when a WebUI Tab Strip thumbnail is dropped into overview grid.
  void MergeWindowIntoOverviewForWebUITabStrip(aura::Window* dragged_window);

  // Shows/Hides windows during window dragging. Used when swiping up a window
  // from shelf.
  void SetVisibleDuringWindowDragging(bool visible, bool animate);

  // Called by |OverviewSession::OnDisplayMetricsChanged|, only for the display
  // with this grid.
  void OnDisplayMetricsChanged(uint32_t changed_metrics);

  // Called by |OverviewSession::OnUserWorkAreaInsetsChanged|.
  void OnUserWorkAreaInsetsChanged(aura::Window* root_window);

  // Called when overview starting animation completes.
  void OnStartingAnimationComplete(bool canceled);

  // Calculates `should_animate_when_entering_` and
  // `should_animate_when_exiting_` of overview items. This to animate only what
  // is necessary for performance reasons. A window will not be animated if
  // both its source and target bounds are covered by another window higher in
  // z-order. For example, if the MRU window is maximized and we have no floated
  // or always on top windows, that window will be the only animated window
  // entering or exiting overview. `selected_item` is the selected item when
  // exiting overview mode, null otherwise. `target_bounds` are the bounds that
  // the items will be in overview. If `tranisition` is exit, `target_bounds`
  // should be empty and the overview bounds should be queried from
  // `item_list_`.
  void CalculateWindowListAnimationStates(
      OverviewItemBase* selected_item,
      OverviewTransition transition,
      const std::vector<gfx::RectF>& target_bounds);

  // Do not animate the entire window list during exiting the overview. It's
  // used when splitview and overview mode are both active, selecting a window
  // will put the window in splitview mode and also end the overview mode. In
  // this case the windows in OverviewGrid should not animate when exiting the
  // overivew mode. These windows will use ZERO tween so that transforms will
  // reset at the end of animation.
  void SetWindowListNotAnimatedWhenExiting();

  // Starts a nudge, with `item` being the item that may be deleted. This method
  // calculates which items in `item_list_` are to be updated, and their
  // destination bounds and fills `nudge_data_` accordingly.
  void StartNudge(OverviewItemBase* item);

  // Moves items in |nudge_data_| towards their destination bounds based on
  // |value|, which must be between 0.0 and 1.0.
  void UpdateNudge(OverviewItemBase* item, double value);

  // Clears |nudge_data_|.
  void EndNudge();

  // Returns the window of the overview item that contains |location_in_screen|.
  // |ignored_item| is excluded from consideration. Overview items covered by
  // |ignored_item| are eligible.
  aura::Window* GetTargetWindowOnLocation(const gfx::PointF& location_in_screen,
                                          OverviewItemBase* ignored_item);

  // Returns true when the desks bar view is showing desks mini views (or will
  // show them once it is created).
  bool IsDesksBarViewActive() const;

  // Gets the effective bounds of this grid (the area in which the windows are
  // positioned, taking into account the availability of the desks bar and birch
  // bar).
  gfx::Rect GetGridEffectiveBounds() const;

  // Gets the horizontal paddings according to the shelf alignment and the
  // existence of split view.
  gfx::Insets GetGridHorizontalPaddings() const;

  // Gets the vertical paddings according to the existence of desk bar, birch
  // bar, shelf and split view.
  gfx::Insets GetGridVerticalPaddings() const;

  // Gets the insets of the grid. Either |bounds_| or GetGridEffectiveBounds
  // does not exclude the insets from its bounds. But like PositionWindows needs
  // to position the overview windows in the bounds exclude the insets.
  gfx::Insets GetGridInsets() const;

  // Called when a window is being dragged in Overview Mode. If
  // |update_desks_bar_drag_details| is true, it will update the drag details
  // (screen_location, and whether that location intersects with the
  // desks bar widget). |for_drop| should be set to true if this is called when
  // the item is being dropped when the drag is complete.
  // Returns true if |screen_location| does intersect with the
  // OverviewDeskBarView.
  bool IntersectsWithDesksBar(const gfx::Point& screen_location,
                              bool update_desks_bar_drag_details,
                              bool for_drop);

  // Updates the drag details for OverviewDeskBarView to end the drag and move
  // the window(s) represented by the `dragged_item` to another desk if it was
  // dropped on a mini_view of a desk that is different than that of the active
  // desk or if dropped on the new desk button. Returns true if the window(s)
  // were successfully moved to another desk.
  bool MaybeDropItemOnDeskMiniViewOrNewDeskButton(
      const gfx::Point& screen_location,
      OverviewItemBase* dragged_item);

  // Prepares the |scroll_offset_min_| as a limit for |scroll_offset| from
  // scrolling or positioning windows too far offscreen.
  void StartScroll();

  // |delta| is used for updating |scroll_offset_| with new scroll values so
  // that windows in tablet overview mode get positioned accordingly. Returns
  // true if the grid was moved to the edge.
  bool UpdateScrollOffset(float delta);

  void EndScroll();

  // Calculates the width of an item based on |height|. The width tries to keep
  // the same aspect ratio as the original window, but may be modified if the
  // bounds of the window are considered extreme, or if the window is in
  // splitview or entering splitview.
  int CalculateWidthAndMaybeSetUnclippedBounds(OverviewItemBase* item,
                                               int height);

  // Returns true if any desk name is being modified in its mini view on this
  // grid.
  bool IsDeskNameBeingModified() const;

  // Commits any on-going name changes if any.
  void CommitNameChanges();

  // Shows the saved desk library. Creates the widget if needed. The desks bar
  // will be expanded if it isn't already.
  void ShowSavedDeskLibrary();

  // Hides the saved desk library and reshows the overview items. Updates the
  // save desk buttons if we are not exiting overview.
  void HideSavedDeskLibrary(bool exit_overview);

  // True if the saved desk library is shown, or in the process of animating to
  // be shown.
  bool IsShowingSavedDeskLibrary() const;

  // Returns true if any saved desk name is being modified in its item view on
  // this grid.
  bool IsSavedDeskNameBeingModified() const;

  // Updates the visibility of the `no_windows_widget_`. If `no_items` is true,
  // the widget will be shown. If `no_items` is false or the desk templates grid
  // is visible, the widget will be hidden.
  void UpdateNoWindowsWidget(bool no_items,
                             bool animate,
                             bool is_continuous_enter);

  // Refreshes this grid's bounds. This will set bounds and update the overview
  // item positions depending on the current split view state.
  void RefreshGridBounds(bool animate);

  // Updates bounds, tooltips and a11y focus, as well as handles animations on
  // `save_desk_button_container_widget_`.
  void UpdateSaveDeskButtons();

  // Enable the save desk button container.
  void EnableSaveDeskButtonContainer();

  bool IsSaveDeskButtonContainerVisible() const;
  bool IsSaveDeskAsTemplateButtonVisible() const;
  bool IsSaveDeskForLaterButtonVisible() const;

  // Called by `OverviewSession` when tablet mode changes to update necessary UI
  // if needed.
  void OnTabletModeChanged();

  // This is different from `item_list_.size()` which contains the drop target
  // if it exists, and if two windows are in a snap group, they are a single
  // item.
  size_t GetNumWindows() const;

  // Returns the save desk as template button if available, otherwise null.
  SavedDeskSaveDeskButton* GetSaveDeskAsTemplateButton();

  // Returns the save desk for later button if available, otherwise null.
  SavedDeskSaveDeskButton* GetSaveDeskForLaterButton();

  // Returns the save button container if available, otherwise null.
  SavedDeskSaveDeskButtonContainer* GetSaveDeskButtonContainer();
  const SavedDeskSaveDeskButtonContainer* GetSaveDeskButtonContainer() const;

  const SplitViewSetupView* GetSplitViewSetupView() const;

  // Gets the cropping area of the wallpaper in screen coordinates.
  gfx::Rect GetWallpaperClipBounds() const;

  // Initializes the widget that contains the `BirchBarView` contents.`by_user`
  // is true, if the user selects to show the birch bar from the context menu.
  void MaybeInitBirchBarWidget(bool by_user = false);

  // Shuts down birch bar widget, when the user selects to hide the birch bar
  // from the context menu.
  void ShutdownBirchBarWidgetByUser();

  // Destroys the birch bar widget, clears pointers and refresh grids. `by_user`
  // is true when the birch bar is disabled by user.
  void DestroyBirchBarWidget(bool by_user = false);

  // SplitViewObserver:
  void OnSplitViewStateChanged(SplitViewController::State previous_state,
                               SplitViewController::State state) override;
  void OnSplitViewDividerPositionChanged() override;

  // ScreenRotationAnimatorObserver:
  void OnScreenCopiedBeforeRotation() override;
  void OnScreenRotationAnimationFinished(ScreenRotationAnimator* animator,
                                         bool canceled) override;

  // WallpaperControllerObserver:
  void OnWallpaperChanging() override;
  void OnWallpaperChanged() override;

  // OverviewItem::WindowDestructionDelegate:
  void OnOverviewItemWindowDestroying(OverviewItem* overview_item,
                                      bool reposition) override;

  // Returns the saved desk library view, or nullptr.
  SavedDeskLibraryView* GetSavedDeskLibraryView();
  const SavedDeskLibraryView* GetSavedDeskLibraryView() const;

  // Returns true if the grid has no more items.
  bool empty() const { return item_list_.empty(); }

  const OverviewDropTarget* drop_target() const { return drop_target_; }

  // Returns the root window in which the grid displays the windows.
  aura::Window* root_window() { return root_window_; }
  const aura::Window* root_window() const { return root_window_; }

  OverviewSession* overview_session() { return overview_session_; }

  const std::vector<std::unique_ptr<OverviewItemBase>>& item_list() const {
    return item_list_;
  }

  const SplitViewDragIndicators* split_view_drag_indicators() const {
    return split_view_drag_indicators_.get();
  }

  bool should_animate_when_exiting() const {
    return should_animate_when_exiting_;
  }

  void set_suspend_reposition(bool value) { suspend_reposition_ = value; }

  OverviewGridEventHandler* grid_event_handler() {
    return grid_event_handler_.get();
  }

  aura::Window* dragged_window() { return dragged_window_.get(); }

  // TODO(sammiequon): Remove some of these getters by using friend or helper
  // function.
  RoundedLabelWidget* no_windows_widget() { return no_windows_widget_.get(); }

  const views::Widget* desks_widget() const { return desks_widget_.get(); }
  views::Widget* desks_widget() { return desks_widget_.get(); }

  const OverviewDeskBarView* desks_bar_view() const { return desks_bar_view_; }
  OverviewDeskBarView* desks_bar_view() { return desks_bar_view_; }

  views::Widget* birch_bar_widget() { return birch_bar_widget_.get(); }

  views::Widget* split_view_setup_widget() {
    return split_view_setup_widget_.get();
  }

  views::Widget* saved_desk_library_widget() {
    return saved_desk_library_widget_.get();
  }

  views::Widget* informed_restore_widget() {
    return informed_restore_widget_.get();
  }
  const views::Widget* informed_restore_widget() const {
    return informed_restore_widget_.get();
  }

  views::Widget* save_desk_button_container_widget() {
    return save_desk_button_container_widget_.get();
  }

  ScopedOverviewWallpaperClipper* scoped_overview_wallpaper_clipper() {
    return scoped_overview_wallpaper_clipper_.get();
  }

  int num_incognito_windows() const { return num_incognito_windows_; }

  int num_unsupported_windows() const { return num_unsupported_windows_; }

  SaveDeskOptionStatus GetEnableStateAndTooltipIDForTemplateType(
      DeskTemplateType type) const;

  base::WeakPtr<OverviewGrid> GetWeakPtr() {
    return weak_ptr_factory_.GetWeakPtr();
  }

 private:
  friend class DesksTemplatesTest;
  friend class OverviewGridTestApi;
  friend class OverviewTestBase;

  // Struct which holds data required to perform nudges. Nudge in the context of
  // overview view means an overview item is currently being dragged vertically
  // and may be closed when released, and the remaining windows will move
  // towards their positions once the item is closed.
  struct OverviewNudgeData {
    size_t index;
    gfx::RectF src;
    gfx::RectF dst;
  };

  // Initializes the widget that contains the `OverviewDeskBarView` contents.
  // Also will update the save desk buttons visibility after we initialize
  // `OverviewDeskBarView`.
  void MaybeInitDesksWidget();

  // Gets the layout of the overview items. Layout is done in 2 stages
  // maintaining fixed MRU ordering.
  // 1. Optimal height is determined. In this stage `height` is bisected to find
  //    maximum height which still allows all the windows to fit.
  // 2. Row widths are balanced. In this stage the available width is reduced
  //    until some windows are no longer fitting or until the difference between
  //    the narrowest and the widest rows starts growing.
  // Overall this achieves the goals of maximum size for previews (or maximum
  // row height which is equivalent assuming fixed height), balanced rows and
  // minimal wasted space.
  std::vector<gfx::RectF> GetWindowRects(
      const base::flat_set<OverviewItemBase*>& ignored_items);

  // Gets the layout of the overview items. Currently only for tablet mode.
  // Positions up to six windows into two rows of equal height, scaling each
  // window to fit that height. Additional windows are placed off-screen.
  // `ignored_items` won't be shown along with the other windows in overview
  // mode.
  std::vector<gfx::RectF> GetWindowRectsForScrollingLayout(
      const base::flat_set<OverviewItemBase*>& ignored_items);

  // Attempts to fit all |out_rects| inside |bounds|. The method ensures that
  // the |out_rects| vector has appropriate size and populates it with the
  // values placing rects next to each other left-to-right in rows of equal
  // |height|. While fitting |out_rects| several metrics are collected that can
  // be used by the caller. |out_max_bottom| specifies the bottom that the rects
  // are extending to. |out_min_right| and |out_max_right| report the right
  // bound of the narrowest and the widest rows respectively. In-values of the
  // |out_max_bottom|, |out_min_right| and |out_max_right| parameters are
  // ignored and their values are always initialized inside this method. Returns
  // true on success and false otherwise.
  bool FitWindowRectsInBounds(
      const gfx::Rect& bounds,
      int height,
      const base::flat_set<OverviewItemBase*>& ignored_items,
      std::vector<gfx::RectF>* out_rects,
      int* out_max_bottom,
      int* out_min_right,
      int* out_max_right);

  // Maybe modify `out_window_rects` to center the overview items excluding the
  // the rect(s) corresponding to item(s) in `ignored_items`.
  void MaybeCenterOverviewItems(
      const base::flat_set<OverviewItemBase*>& ignored_items,
      std::vector<gfx::RectF>& out_window_rects);

  // Returns the index of `item` in `item_list_`.
  size_t GetOverviewItemIndex(OverviewItemBase* item) const;

  // Returns the index where `window` can be inserted into `item_list_` based
  // on MRU order.
  size_t FindInsertionIndex(const aura::Window* window) const;

  // Adds the |dragged_window| into overview on drag ended. Might need to update
  // the window's bounds if it has been resized.
  void AddDraggedWindowIntoOverviewOnDragEnd(aura::Window* dragged_window);

  // Returns the the bounds of the desks widget in screen coordinates.
  gfx::Rect GetDesksWidgetBounds() const;

  // Returns the bounds of the birch bar widget in the screen coordinates.
  gfx::Rect GetBirchBarWidgetBounds() const;

  void UpdateCannotSnapWarningVisibility(bool animate);

  // Called back when the button to save desk as template button is pressed.
  void OnSaveDeskAsTemplateButtonPressed();

  // Called back when the button to save a desk for later is pressed.
  void OnSaveDeskForLaterButtonPressed();

  // Called when the animation for fading the `saved_desk_grid_widget_` out is
  // completed.
  void OnSavedDeskGridFadedOut();

  // Called when the animation for fading the
  // `save_desk_button_container_widget_` out is completed.
  void OnSaveDeskButtonContainerFadedOut();

  // Called when the layout of the birch bar is updated. We may need to
  // reposition the windows if the relayout is due to the contents change.
  void OnBirchBarLayoutChanged(BirchBarView::RelayoutReason reason);

  // Refreshes desks widgets visibility: hidden in partial Overview, visibility
  // restored when partial Overview ends.
  void RefreshDesksWidgets(bool visible);

  // Updates the number of unsupported windows of saved desk. This includes
  // `num_incognito_windows_` and `num_unsupported_windows` as of now. When
  // the overview item that represents the `windows` is being added to `this`,
  // `increment` is true, and false if being removed.
  void UpdateNumSavedDeskUnsupportedWindows(
      const std::vector<raw_ptr<aura::Window, VectorExperimental>>& windows,
      bool increment);

  // Returns the height of `desks_bar_view_`.
  int GetDesksBarHeight() const;

  bool ShouldUseScrollingLayout(size_t ignored_items_size) const;

  // Creates the drop target, which lets users know where `dragged_item` will
  // land. Adds the drop target to `item_list_` at `position` (which is
  // usually the index of `dragged_item`), and calls `PositionWindows()`.
  void AddDropTargetImpl(OverviewItemBase* dragged_item,
                         size_t position,
                         bool animate);

  // Called when the split view setup view toast skip button is pressed.
  void OnSkipButtonPressed();

  // Called when the split view setup view settings button is pressed.
  void OnSettingsButtonPressed();

  // Updates the visibility of `split_view_setup_widget_`. The widget will
  // only be shown if split view overview is in session.
  void UpdateSplitViewSetupViewWidget();

  // Whether the `desks_widget_` should be initialized.
  bool ShouldInitDesksWidget() const;

  // The drop target is created when a window or overview item is being dragged,
  // and is destroyed when the drag ends or overview mode is ended. The drop
  // target is hidden when a snap preview area is shown. You can drop a window
  // into overview by dragging to the drop target or by dragging to almost
  // anywhere while the drop target is shown. The drop target is owned by
  // `item_list_`; this is just a convenience pointer.
  raw_ptr<OverviewDropTarget> drop_target_ = nullptr;

  // Root window the grid is in.
  raw_ptr<aura::Window, DanglingUntriaged> root_window_;

  // Pointer to the OverviewSession that spawned this grid.
  raw_ptr<OverviewSession> overview_session_;

  // Vector containing all the items in this grid.
  std::vector<std::unique_ptr<OverviewItemBase>> item_list_;

  // The owner of the widget that displays split-view-related information. Null
  // if split view is unsupported (see |ShouldAllowSplitView|).
  std::unique_ptr<SplitViewDragIndicators> split_view_drag_indicators_;

  // A widget that is shown if we entered overview without any windows opened.
  std::unique_ptr<RoundedLabelWidget> no_windows_widget_;

  // Widget that contains the DeskBarView contents when the Virtual Desks
  // feature is enabled.
  std::unique_ptr<views::Widget> desks_widget_;

  // The contents view of the above |desks_widget_| if created.
  raw_ptr<OverviewDeskBarView, DanglingUntriaged> desks_bar_view_ = nullptr;

  // Widget that contains the BirchBarView contents when the Forest feature is
  // enabled.
  std::unique_ptr<views::Widget> birch_bar_widget_;

  // The contents view of the `birch_bar_widget_` if created.
  raw_ptr<BirchBarView> birch_bar_view_ = nullptr;

  // Widget that appears during the split view setup. Contains the split view
  // setup view toast and settings button.
  std::unique_ptr<views::Widget> split_view_setup_widget_;

  // The widget that contains the view for all saved desks.
  std::unique_ptr<views::Widget> saved_desk_library_widget_;

  // The widget that contains the `InformedRestoreContentsView`.
  std::unique_ptr<views::Widget> informed_restore_widget_;

  // A widget that contains save desk buttons which save desk as template or for
  // later when pressed.
  std::unique_ptr<views::Widget> save_desk_button_container_widget_;

  // True if the overview grid should animate when exiting overview mode. Note
  // even if it's true, it doesn't mean all window items in the grid should
  // animate when exiting overview, instead each window item's animation status
  // is controlled by its own |should_animate_when_exiting_|. But if it's false,
  // all window items in the grid don't have animation.
  bool should_animate_when_exiting_ = true;

  // This OverviewGrid's total bounds in screen coordinates.
  gfx::Rect bounds_;

  // Collection of the items which should be nudged. This should only be
  // non-empty if a nudge is in progress.
  std::vector<OverviewNudgeData> nudge_data_;

  // Measures the animation smoothness of overview animation.
  std::unique_ptr<MetricsTracker> metrics_tracker_;

  // True to skip |PositionWindows()|. Used to avoid O(n^2) layout when
  // reposition windows in tablet overview mode.
  bool suspend_reposition_ = false;

  // Used by `GetWindowRectsForScrollingLayout()` to shift the x position of the
  // overview items.
  float scroll_offset_ = 0;

  // Value to clamp `scroll_offset_` so scrolling stays limited to windows that
  // are visible in tablet overview mode.
  float scroll_offset_min_ = 0.f;

  // Handles events that are not handled by the OverviewItems.
  std::unique_ptr<OverviewGridEventHandler> grid_event_handler_;

  // Hides scoped windows in partial overview, restores their visibility when
  // partial overview ends.
  std::unique_ptr<ScopedOverviewHideWindows> hide_windows_in_partial_overview_;

  // Records the presentation time of scrolling the grid in overview mode.
  std::unique_ptr<ui::PresentationTimeRecorder> presentation_time_recorder_;

  // Window that is being dragged from the shelf or during tab dragging.
  raw_ptr<aura::Window> dragged_window_ = nullptr;

  //  A scoped object responsible for managing wallpaper clipping transitions
  //  during overview mode.
  std::unique_ptr<ScopedOverviewWallpaperClipper>
      scoped_overview_wallpaper_clipper_;

  // The number of incognito windows in this grid. Used by saved desks to
  // identify the unsupported window type to the user.
  int num_incognito_windows_ = 0;

  // The number of unsupported windows in this grid. Used by saved desks to
  // identify the unsupported window type to the user.
  int num_unsupported_windows_ = 0;

  // Used when feature ContinuousOverviewScrollAnimation is enabled. When a
  // continuous scroll starts, store the calculated target transforms here. For
  // each scroll update, use this list to prevent unnecessary recalculations.
  // For a scroll end, clear the list.
  base::flat_map<OverviewItemBase*, gfx::Transform> cached_transforms_;

  std::optional<OverviewController::ScopedOcclusionPauser> rotation_pauser_;
  std::optional<OverviewController::ScopedOcclusionPauser> scroll_pauser_;

  const base::WeakPtr<WindowOcclusionCalculator> window_occlusion_calculator_;

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

}  // namespace ash

#endif  // ASH_WM_OVERVIEW_OVERVIEW_GRID_H_