chromium/ash/wm/always_on_top_controller_unittest.cc

// 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.

#include "ash/wm/always_on_top_controller.h"

#include "ash/keyboard/keyboard_controller_impl.h"
#include "ash/keyboard/ui/keyboard_ui.h"
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/keyboard/ui/test/keyboard_test_util.h"
#include "ash/public/cpp/keyboard/keyboard_switches.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.h"
#include "ash/wm/workspace/workspace_layout_manager.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "ui/aura/client/aura_constants.h"

namespace ash {

class AlwaysOnTopControllerTest : public AshTestBase {
 public:
  AlwaysOnTopControllerTest() = default;

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

  ~AlwaysOnTopControllerTest() override = default;

  void SetUp() override {
    base::CommandLine::ForCurrentProcess()->AppendSwitch(
        keyboard::switches::kEnableVirtualKeyboard);
    AshTestBase::SetUp();
  }
};

class TestLayoutManager : public WorkspaceLayoutManager {
 public:
  explicit TestLayoutManager(aura::Window* window)
      : WorkspaceLayoutManager(window),
        keyboard_displacing_bounds_changed_(false) {}

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

  ~TestLayoutManager() override = default;

  void OnKeyboardDisplacingBoundsChanged(const gfx::Rect& bounds) override {
    keyboard_displacing_bounds_changed_ = true;
    WorkspaceLayoutManager::OnKeyboardDisplacingBoundsChanged(bounds);
  }

  bool keyboard_displacing_bounds_changed() const {
    return keyboard_displacing_bounds_changed_;
  }

 private:
  bool keyboard_displacing_bounds_changed_;
};

// Verifies that the always on top controller is notified of keyboard bounds
// changing events.
TEST_F(AlwaysOnTopControllerTest, NotifyKeyboardBoundsChanging) {
  aura::Window* root_window = Shell::GetPrimaryRootWindow();
  aura::Window* always_on_top_container =
      Shell::GetContainer(root_window, kShellWindowId_AlwaysOnTopContainer);
  // Install test layout manager.
  TestLayoutManager* manager = new TestLayoutManager(always_on_top_container);
  RootWindowController* controller = Shell::GetPrimaryRootWindowController();
  AlwaysOnTopController* always_on_top_controller =
      controller->always_on_top_controller();
  always_on_top_controller->SetLayoutManagerForTest(base::WrapUnique(manager));

  // Show the keyboard to change the displacing bounds.
  auto* keyboard_controller = keyboard::KeyboardUIController::Get();
  keyboard_controller->SetKeyboardWindowBounds(gfx::Rect(0, 0, 100, 100));
  EXPECT_FALSE(manager->keyboard_displacing_bounds_changed());

  keyboard_controller->ShowKeyboard(true /* locked */);
  ASSERT_TRUE(keyboard::test::WaitUntilShown());

  // Verify that test manager was notified of bounds change.
  EXPECT_TRUE(manager->keyboard_displacing_bounds_changed());
}

TEST_F(AlwaysOnTopControllerTest,
       AlwaysOnTopContainerReturnedForFloatingWindow) {
  RootWindowController* controller = Shell::GetPrimaryRootWindowController();
  AlwaysOnTopController* always_on_top_controller =
      controller->always_on_top_controller();

  const gfx::Rect bounds(100, 100, 200, 200);
  std::unique_ptr<aura::Window> always_on_top_window(
      CreateTestWindowInShellWithBounds(bounds));
  always_on_top_window->SetProperty(aura::client::kZOrderingKey,
                                    ui::ZOrderLevel::kFloatingWindow);

  aura::Window* container =
      always_on_top_controller->GetContainer(always_on_top_window.get());
  ASSERT_TRUE(container);
  EXPECT_EQ(kShellWindowId_AlwaysOnTopContainer, container->GetId());
}

TEST_F(AlwaysOnTopControllerTest, PipContainerReturnedForFloatingPipWindow) {
  RootWindowController* controller = Shell::GetPrimaryRootWindowController();
  AlwaysOnTopController* always_on_top_controller =
      controller->always_on_top_controller();

  const gfx::Rect bounds(100, 100, 200, 200);
  std::unique_ptr<aura::Window> pip_window(
      CreateTestWindowInShellWithBounds(bounds));

  WindowState* window_state = WindowState::Get(pip_window.get());
  const WMEvent enter_pip(WM_EVENT_PIP);
  window_state->OnWMEvent(&enter_pip);
  pip_window->SetProperty(aura::client::kZOrderingKey,
                          ui::ZOrderLevel::kFloatingWindow);
  EXPECT_TRUE(window_state->IsPip());

  aura::Window* container =
      always_on_top_controller->GetContainer(pip_window.get());
  ASSERT_TRUE(container);
  EXPECT_EQ(kShellWindowId_PipContainer, container->GetId());
}

TEST_F(AlwaysOnTopControllerTest,
       DefaultContainerReturnedForWindowNotAlwaysOnTop) {
  RootWindowController* controller = Shell::GetPrimaryRootWindowController();
  AlwaysOnTopController* always_on_top_controller =
      controller->always_on_top_controller();

  const gfx::Rect bounds(100, 100, 200, 200);
  std::unique_ptr<aura::Window> window(
      CreateTestWindowInShellWithBounds(bounds));

  aura::Window* container =
      always_on_top_controller->GetContainer(window.get());
  ASSERT_TRUE(container);
  EXPECT_EQ(desks_util::GetActiveDeskContainerId(), container->GetId());
}

TEST_F(AlwaysOnTopControllerTest,
       FloatingWindowMovedBetweenContainersWhenPipStateChanges) {
  const gfx::Rect bounds(100, 100, 200, 200);
  std::unique_ptr<aura::Window> window(
      CreateTestWindowInShellWithBounds(bounds));
  window->SetProperty(aura::client::kZOrderingKey,
                      ui::ZOrderLevel::kFloatingWindow);

  EXPECT_EQ(kShellWindowId_AlwaysOnTopContainer, window->parent()->GetId());

  WindowState* window_state = WindowState::Get(window.get());
  const WMEvent enter_pip(WM_EVENT_PIP);
  window_state->OnWMEvent(&enter_pip);
  EXPECT_TRUE(window_state->IsPip());

  EXPECT_EQ(kShellWindowId_PipContainer, window->parent()->GetId());

  const WMEvent enter_normal(WM_EVENT_NORMAL);
  window_state->OnWMEvent(&enter_normal);
  EXPECT_FALSE(window_state->IsPip());

  EXPECT_EQ(kShellWindowId_AlwaysOnTopContainer, window->parent()->GetId());
}

}  // namespace ash