chromium/ash/wm/splitview/split_view_test_util.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/splitview/split_view_test_util.h"

#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_constants.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
#include "ash/wm/overview/overview_grid_test_api.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/overview/overview_test_util.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/snap_group/snap_group.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_divider.h"
#include "ash/wm/splitview/split_view_overview_session.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/wm/core/coordinate_conversion.h"

namespace ash {

gfx::Rect GetOverviewGridBounds(aura::Window* root_window) {
  OverviewSession* overview_session = GetOverviewSession();
  return overview_session ? OverviewGridTestApi(root_window).bounds()
                          : gfx::Rect();
}

SplitViewController* GetSplitViewController() {
  return SplitViewController::Get(Shell::GetPrimaryRootWindow());
}

SplitViewDivider* GetSplitViewDivider() {
  return GetSplitViewController()->split_view_divider();
}

gfx::Rect GetSplitViewDividerBoundsInScreen() {
  return GetSplitViewDivider()->GetDividerBoundsInScreen(
      /*is_dragging=*/false);
}

const gfx::Rect GetWorkAreaBounds() {
  return display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
}

const gfx::Rect GetWorkAreaBoundsForWindow(aura::Window* window) {
  return display::Screen::GetScreen()
      ->GetDisplayNearestWindow(window)
      .work_area();
}

void SnapOneTestWindow(aura::Window* window,
                       chromeos::WindowStateType state_type,
                       float snap_ratio,
                       WindowSnapActionSource snap_action_source) {
  WindowState* window_state = WindowState::Get(window);
  const WindowSnapWMEvent snap_event(
      state_type == chromeos::WindowStateType::kPrimarySnapped
          ? WM_EVENT_SNAP_PRIMARY
          : WM_EVENT_SNAP_SECONDARY,
      snap_ratio, snap_action_source);
  window_state->OnWMEvent(&snap_event);
  EXPECT_EQ(state_type, window_state->GetStateType());
}

void VerifySplitViewOverviewSession(aura::Window* window) {
  auto* overview_controller = OverviewController::Get();
  ASSERT_TRUE(overview_controller->InOverviewSession());
  EXPECT_FALSE(
      overview_controller->overview_session()->IsWindowInOverview(window));

  auto* root_window = window->GetRootWindow();
  auto* split_view_controller = SplitViewController::Get(root_window);
  EXPECT_TRUE(split_view_controller->InSplitViewMode());
  EXPECT_TRUE(split_view_controller->IsWindowInSplitView(window));

  EXPECT_TRUE(GetSplitViewOverviewSession(window));

  gfx::Rect expected_grid_bounds = GetWorkAreaBoundsForWindow(window);
  expected_grid_bounds.Subtract(window->GetBoundsInScreen());

  if (auto* divider = GetSplitViewDivider();
      divider && divider->divider_widget()) {
    expected_grid_bounds.Subtract(GetSplitViewDividerBoundsInScreen());
  }

  // Clamp the length on the side that can be shrunk by resizing to avoid going
  // below the threshold i.e. `kOverviewGridClampThresholdRatio` of the
  // corresponding work area length.
  const bool is_horizontal = IsLayoutHorizontal(Shell::GetPrimaryRootWindow());
  const int min_length = (is_horizontal ? GetWorkAreaBounds().width()
                                        : GetWorkAreaBounds().height()) *
                         kOverviewGridClampThresholdRatio;
  if (is_horizontal) {
    expected_grid_bounds.set_width(
        std::max(expected_grid_bounds.width(), min_length));
  } else {
    expected_grid_bounds.set_height(
        std::max(expected_grid_bounds.height(), min_length));
  }

  if (!Shell::Get()->IsInTabletMode()) {
    EXPECT_EQ(expected_grid_bounds, GetOverviewGridBounds(root_window));
  }

  EXPECT_TRUE(
      expected_grid_bounds.Contains(GetOverviewGridBounds(root_window)));

  if (!Shell::Get()->IsInTabletMode()) {
    auto* overview_grid = GetOverviewGridForRoot(window->GetRootWindow());
    EXPECT_TRUE(overview_grid->split_view_setup_widget());
    EXPECT_FALSE(overview_grid->no_windows_widget());
    // TODO(b/345814268): Consider destroying the widgets.
    const auto* save_desk_widget =
        overview_grid->save_desk_button_container_widget();
    EXPECT_FALSE(save_desk_widget && save_desk_widget->IsVisible());
    const auto* desks_bar_widget = overview_grid->desks_widget();
    EXPECT_FALSE(desks_bar_widget && desks_bar_widget->IsVisible());
  }
}

void VerifyNotSplitViewOrOverviewSession(aura::Window* window) {
  EXPECT_FALSE(IsInOverviewSession());
  EXPECT_FALSE(
      SplitViewController::Get(window->GetRootWindow())->InSplitViewMode());
  EXPECT_FALSE(
      RootWindowController::ForWindow(window)->split_view_overview_session());
}

}  // namespace ash