chromium/ash/wm/splitview/split_view_overview_session.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 ASH_WM_SPLITVIEW_SPLIT_VIEW_OVERVIEW_SESSION_H_
#define ASH_WM_SPLITVIEW_SPLIT_VIEW_OVERVIEW_SESSION_H_

#include <optional>

#include "ash/wm/overview/overview_metrics.h"
#include "ash/wm/overview/overview_types.h"
#include "ash/wm/window_state_observer.h"
#include "ash/wm/wm_metrics.h"
#include "base/scoped_observation.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/presentation_time_recorder.h"

namespace ui {
class LocatedEvent;
}  // namespace ui

namespace ash {

// Defines two ways to get the split overview session in clamshell mode:
// 1. Snap a window and partial overview will automatically show on the other
// side of the screen. Currently behind the feature flag of `kSnapGroup` arm 1
// or `kFasterSplitScreenSetup`;
// 2. In overview session, manually snap a window.
enum class SplitViewOverviewSetupType {
  kSnapThenAutomaticOverview,
  kOverviewThenManualSnap,
  kMaxValue = kOverviewThenManualSnap,
};

// Enumeration of the exit point of the `SplitViewOverviewSession`.
// Please keep in sync with "SplitViewOverviewSessionExitPoint" in
// tools/metrics/histograms/metadata/ash/enums.xml.
enum class SplitViewOverviewSessionExitPoint {
  kCompleteByActivating,
  kSkip,
  kWindowDestroy,
  kShutdown,
  kUnspecified,
  kTabletConversion,
  kMaxValue = kTabletConversion,
};

// Encapsulates the split view state with a single snapped window and
// overview in **clamshell**, also known as intermediate split view or the snap
// group creation session.
//
// While `this` is alive, both split view and overview will be active. `this`
// will automatically be destroyed upon split view or overview ending.
//
// There may be at most one SplitViewOverviewSession per root window. Consumers
// should create and manage this via the
// `RootWindowController::ForWindow(aura::Window*)` function.
//
// Note that clamshell split view does *not* have a divider, and resizing
// overview is done via resizing the window directly.
class ASH_EXPORT SplitViewOverviewSession : public aura::WindowObserver,
                                            public WindowStateObserver {
 public:
  SplitViewOverviewSession(aura::Window* window,
                           WindowSnapActionSource snap_action_source);
  SplitViewOverviewSession(const SplitViewOverviewSession&) = delete;
  SplitViewOverviewSession& operator=(const SplitViewOverviewSession&) = delete;
  ~SplitViewOverviewSession() override;

  aura::Window* window() { return window_; }
  SplitViewOverviewSetupType setup_type() const { return setup_type_; }
  chromeos::WindowStateType GetWindowStateType() const;

  // Initializes the session by starting overview. This must be called after the
  // constructor, as consumers may check if `this` exists.
  void Init(std::optional<OverviewStartAction> action,
            std::optional<OverviewEnterExitType> type);

  // Records the `SplitViewOverviewSessionExitPoint` in uma metrics.
  void RecordSplitViewOverviewSessionExitPointMetrics(
      SplitViewOverviewSessionExitPoint user_action);

  // Handles mouse or touch event forwarded from `OverviewSession`.
  void HandleClickOrTap(const ui::LocatedEvent& event);

  // aura::WindowObserver:
  void OnResizeLoopStarted(aura::Window* window) override;
  void OnResizeLoopEnded(aura::Window* window) override;
  void OnWindowBoundsChanged(aura::Window* window,
                             const gfx::Rect& old_bounds,
                             const gfx::Rect& new_bounds,
                             ui::PropertyChangeReason reason) override;
  void OnWindowDestroying(aura::Window* window) override;

  // WindowStateObserver:
  void OnPreWindowStateTypeChange(WindowState* window_state,
                                  chromeos::WindowStateType old_type) override;

  WindowSnapActionSource snap_action_source_for_testing() const {
    return snap_action_source_;
  }

 private:
  // Maybe ends overview or `this` based on the `setup_type_`.
  void MaybeEndOverview(SplitViewOverviewSessionExitPoint exit_point,
                        OverviewEnterExitType exit_type);

  // True while we are processing a window resize event.
  bool is_resizing_ = false;

  // Records the presentation time of resize operation in clamshell split view
  // mode.
  std::unique_ptr<ui::PresentationTimeRecorder> presentation_time_recorder_;

  // The single snapped window in intermediate split view, with overview on
  // the opposite side.
  const raw_ptr<aura::Window> window_;

  SplitViewOverviewSetupType setup_type_ =
      SplitViewOverviewSetupType::kSnapThenAutomaticOverview;

  // Stores the snap action source info for the snapped `window_`.
  const WindowSnapActionSource snap_action_source_;

  base::ScopedObservation<aura::Window, aura::WindowObserver>
      window_observation_{this};
};

}  // namespace ash

#endif  // ASH_WM_SPLITVIEW_SPLIT_VIEW_OVERVIEW_SESSION_H_