blob: e166fb285afd205802dfa11aa2782758608af7d7 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/ws/focus_handler.h"
#include <stdint.h>
#include <memory>
#include <queue>
#include "services/ws/event_test_utils.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "services/ws/window_service.h"
#include "services/ws/window_service_test_setup.h"
#include "services/ws/window_tree_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/wm/core/focus_controller.h"
namespace ws {
namespace {
TEST(FocusHandlerTest, FocusTopLevel) {
WindowServiceTestSetup setup;
aura::Window* top_level =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level);
// SetFocus() should fail as |top_level| isn't visible.
EXPECT_FALSE(setup.window_tree_test_helper()->SetFocus(top_level));
top_level->Show();
EXPECT_TRUE(setup.window_tree_test_helper()->SetFocus(top_level));
EXPECT_TRUE(top_level->HasFocus());
}
// This test simulates the typical sequence of a client closing a window Hide().
// Note that SetFocus(nullptr) shouldn't happen.
TEST(FocusHandlerTest, FocusChangesAfterHide) {
// Create two top-levels and focus the second.
WindowServiceTestSetup setup;
aura::Window* top_level1 =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level1);
top_level1->Show();
aura::Window* top_level2 =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level2);
top_level2->Show();
EXPECT_TRUE(setup.window_tree_test_helper()->SetFocus(top_level2));
EXPECT_TRUE(top_level2->HasFocus());
// Hiding |top_level2| should focus |top_level1|.
setup.changes()->clear();
top_level2->Hide();
EXPECT_FALSE(top_level2->HasFocus());
EXPECT_TRUE(top_level1->HasFocus());
EXPECT_TRUE(ContainsChange(*setup.changes(), "Focused id=0,1"));
}
TEST(FocusHandlerTest, FocusChild) {
WindowServiceTestSetup setup;
aura::Window* top_level =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level);
top_level->Show();
aura::Window* window = setup.window_tree_test_helper()->NewWindow();
ASSERT_TRUE(window);
// SetFocus() should fail as |window| isn't parented yet.
EXPECT_FALSE(setup.window_tree_test_helper()->SetFocus(window));
top_level->AddChild(window);
// SetFocus() should still fail as |window| isn't visible.
EXPECT_FALSE(setup.window_tree_test_helper()->SetFocus(window));
setup.window_tree_test_helper()->SetCanFocus(window, false);
window->Show();
// SetFocus() should fail as SetCanFocus(false) was called.
EXPECT_FALSE(setup.window_tree_test_helper()->SetFocus(window));
setup.window_tree_test_helper()->SetCanFocus(window, true);
EXPECT_TRUE(setup.window_tree_test_helper()->SetFocus(window));
}
// Regression test for https://crbug.com/880533
TEST(FocusHandlerTest, FocusChildOfActiveWindow) {
WindowServiceTestSetup setup;
aura::Window* top_level =
setup.window_tree_test_helper()->NewTopLevelWindow();
top_level->Show();
setup.focus_controller()->ActivateWindow(top_level);
EXPECT_EQ(top_level, setup.focus_controller()->GetActiveWindow());
aura::Window* child = setup.window_tree_test_helper()->NewWindow();
top_level->AddChild(child);
child->Show();
EXPECT_TRUE(setup.window_tree_test_helper()->SetFocus(child));
EXPECT_TRUE(child->HasFocus());
}
TEST(FocusHandlerTest, NotifyOnFocusChange) {
WindowServiceTestSetup setup;
aura::Window* top_level =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level);
top_level->Show();
aura::Window* window1 = setup.window_tree_test_helper()->NewWindow();
ASSERT_TRUE(window1);
top_level->AddChild(window1);
window1->Show();
aura::Window* window2 = setup.window_tree_test_helper()->NewWindow(4);
ASSERT_TRUE(window2);
top_level->AddChild(window2);
window2->Show();
setup.changes()->clear();
// Window is parented and visible, so SetFocus() should succeed.
EXPECT_TRUE(setup.window_tree_test_helper()->SetFocus(window1));
// As the client originated the request it is not notified of the change.
EXPECT_TRUE(setup.changes()->empty());
// Focus |window2| locally (not from the client), which should result in
// notifying the client.
window2->Focus();
EXPECT_TRUE(window2->HasFocus());
EXPECT_EQ("Focused id=0,4", SingleChangeToDescription(*setup.changes()));
}
TEST(FocusHandlerTest, FocusChangeFromEmbedded) {
WindowServiceTestSetup setup;
aura::Window* top_level =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level);
top_level->Show();
aura::Window* embed_window = setup.window_tree_test_helper()->NewWindow();
ASSERT_TRUE(embed_window);
top_level->AddChild(embed_window);
embed_window->Show();
std::unique_ptr<EmbeddingHelper> embedding_helper =
setup.CreateEmbedding(embed_window);
setup.changes()->clear();
embedding_helper->changes()->clear();
// Set focus from the embedded client.
EXPECT_TRUE(
embedding_helper->window_tree_test_helper->SetFocus(embed_window));
EXPECT_TRUE(embed_window->HasFocus());
EXPECT_TRUE(setup.changes()->empty());
EXPECT_TRUE(embedding_helper->changes()->empty());
// Send an event, the embedded client should get it.
ui::test::EventGenerator event_generator(setup.root());
event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
EXPECT_TRUE(setup.changes()->empty());
EXPECT_EQ(
"KEY_PRESSED",
EventToEventType(
embedding_helper->window_tree_client.PopInputEvent().event.get()));
EXPECT_TRUE(embedding_helper->window_tree_client.input_events().empty());
embedding_helper->changes()->clear();
// Set focus from the parent. The embedded client should lose focus.
setup.window_tree_test_helper()->SetFocus(embed_window);
EXPECT_TRUE(embed_window->HasFocus());
EXPECT_TRUE(setup.changes()->empty());
EXPECT_EQ("Focused id=null",
SingleChangeToDescription(*embedding_helper->changes()));
embedding_helper->changes()->clear();
// And events should now target the parent.
event_generator.PressKey(ui::VKEY_B, ui::EF_NONE);
EXPECT_EQ("KEY_PRESSED",
EventToEventType(
setup.window_tree_client()->PopInputEvent().event.get()));
EXPECT_TRUE(embedding_helper->changes()->empty());
}
TEST(FocusHandlerTest, EmbedderGetsInterceptedKeyEvents) {
WindowServiceTestSetup setup;
aura::Window* top_level =
setup.window_tree_test_helper()->NewTopLevelWindow();
ASSERT_TRUE(top_level);
top_level->Show();
aura::Window* embed_window = setup.window_tree_test_helper()->NewWindow();
ASSERT_TRUE(embed_window);
top_level->AddChild(embed_window);
embed_window->Show();
std::unique_ptr<EmbeddingHelper> embedding_helper = setup.CreateEmbedding(
embed_window, mojom::kEmbedFlagEmbedderInterceptsEvents);
ASSERT_TRUE(embedding_helper);
aura::Window* embed_child_window =
embedding_helper->window_tree_test_helper->NewWindow();
ASSERT_TRUE(embed_child_window);
embed_child_window->Show();
embed_window->AddChild(embed_child_window);
setup.changes()->clear();
embedding_helper->changes()->clear();
// Set focus from the embedded client.
EXPECT_TRUE(
embedding_helper->window_tree_test_helper->SetFocus(embed_child_window));
EXPECT_TRUE(embed_child_window->HasFocus());
// Generate a key-press. Even though focus is on a window in the embedded
// client, the event goes to the embedder because it intercepts events.
ui::test::EventGenerator event_generator(setup.root());
event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
EXPECT_TRUE(embedding_helper->changes()->empty());
EXPECT_TRUE(embedding_helper->window_tree_client.input_events().empty());
EXPECT_EQ("KEY_PRESSED",
EventToEventType(
setup.window_tree_client()->PopInputEvent().event.get()));
}
} // namespace
} // namespace ws