#include "ash/keyboard/virtual_keyboard_controller.h"
#include <utility>
#include <vector>
#include "ash/accessibility/accessibility_controller.h"
#include "ash/ime/ime_controller_impl.h"
#include "ash/ime/test_ime_controller_client.h"
#include "ash/keyboard/keyboard_controller_impl.h"
#include "ash/keyboard/ui/test/keyboard_test_util.h"
#include "ash/public/cpp/keyboard/keyboard_switches.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray_notifier.h"
#include "ash/system/virtual_keyboard/virtual_keyboard_observer.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/tablet_mode/internal_input_devices_event_blocker.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "base/command_line.h"
#include "ui/display/test/display_manager_test_api.h"
#include "ui/events/devices/device_data_manager_test_api.h"
#include "ui/events/devices/input_device.h"
#include "ui/events/devices/keyboard_device.h"
#include "ui/events/devices/touchscreen_device.h"
using keyboard::KeyboardEnableFlag;
namespace ash {
namespace {
VirtualKeyboardController* GetVirtualKeyboardController() {
return Shell::Get()->keyboard_controller()->virtual_keyboard_controller();
}
}
class VirtualKeyboardControllerTest : public AshTestBase {
public:
VirtualKeyboardControllerTest() = default;
VirtualKeyboardControllerTest(const VirtualKeyboardControllerTest&) = delete;
VirtualKeyboardControllerTest& operator=(
const VirtualKeyboardControllerTest&) = delete;
~VirtualKeyboardControllerTest() override = default;
display::Display GetPrimaryDisplay() {
return display::Screen::Get()->GetPrimaryDisplay();
}
display::Display GetSecondaryDisplay() {
return display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
.GetSecondaryDisplay();
}
keyboard::KeyboardUIController* keyboard_ui_controller() {
return keyboard::KeyboardUIController::Get();
}
};
class MockEventBlocker : public InternalInputDevicesEventBlocker {
public:
MockEventBlocker() = default;
MockEventBlocker(const MockEventBlocker&) = delete;
MockEventBlocker& operator=(const MockEventBlocker&) = delete;
~MockEventBlocker() override {
std::vector<ui::KeyboardDevice> keyboard_devices;
keyboard_devices.push_back(ui::KeyboardDevice(
1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
}
};
TEST_F(VirtualKeyboardControllerTest, RestoreKeyboardDevices) {
Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
std::unique_ptr<InternalInputDevicesEventBlocker> blocker(
new MockEventBlocker);
TabletModeControllerTestApi().set_event_blocker(std::move(blocker));
}
TEST_F(VirtualKeyboardControllerTest,
ForceToShowKeyboardWithKeysetWhenAccessibilityKeyboardIsEnabled) {
AccessibilityController* accessibility_controller =
Shell::Get()->accessibility_controller();
accessibility_controller->virtual_keyboard().SetEnabled(true);
ASSERT_TRUE(accessibility_controller->virtual_keyboard().enabled());
TestImeControllerClient client;
Shell::Get()->ime_controller()->SetClient(&client);
GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset(
input_method::ImeKeyset::kEmoji);
EXPECT_TRUE(accessibility_controller->virtual_keyboard().enabled());
EXPECT_EQ(input_method::ImeKeyset::kEmoji, client.last_keyset_);
if (keyboard_ui_controller()->HasObserver(GetVirtualKeyboardController())) {
GetVirtualKeyboardController()->OnKeyboardHidden(
false );
}
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(accessibility_controller->virtual_keyboard().enabled());
accessibility_controller->virtual_keyboard().SetEnabled(false);
EXPECT_EQ(input_method::ImeKeyset::kNone, client.last_keyset_);
Shell::Get()->ime_controller()->SetClient(nullptr);
}
TEST_F(VirtualKeyboardControllerTest,
ForceToShowKeyboardWithKeysetWhenKeyboardIsDisabled) {
TestImeControllerClient client;
Shell::Get()->ime_controller()->SetClient(&client);
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
EXPECT_FALSE(keyboard_ui_controller()->IsEnableFlagSet(
KeyboardEnableFlag::kShelfEnabled));
GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset(
input_method::ImeKeyset::kEmoji);
EXPECT_TRUE(keyboard_ui_controller()->IsEnableFlagSet(
KeyboardEnableFlag::kShelfEnabled));
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_EQ(input_method::ImeKeyset::kEmoji, client.last_keyset_);
if (keyboard_ui_controller()->HasObserver(GetVirtualKeyboardController())) {
GetVirtualKeyboardController()->OnKeyboardHidden(
false );
}
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
EXPECT_FALSE(keyboard_ui_controller()->IsEnableFlagSet(
KeyboardEnableFlag::kShelfEnabled));
EXPECT_EQ(input_method::ImeKeyset::kNone, client.last_keyset_);
}
TEST_F(VirtualKeyboardControllerTest,
ForceToShowKeyboardWithKeysetTemporaryHide) {
TestImeControllerClient client;
Shell::Get()->ime_controller()->SetClient(&client);
GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset(
input_method::ImeKeyset::kEmoji);
EXPECT_TRUE(keyboard_ui_controller()->IsEnableFlagSet(
KeyboardEnableFlag::kShelfEnabled));
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_EQ(input_method::ImeKeyset::kEmoji, client.last_keyset_);
if (keyboard_ui_controller()->HasObserver(GetVirtualKeyboardController())) {
GetVirtualKeyboardController()->OnKeyboardHidden(
true );
}
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(keyboard_ui_controller()->IsEnableFlagSet(
KeyboardEnableFlag::kShelfEnabled));
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_EQ(input_method::ImeKeyset::kEmoji, client.last_keyset_);
}
class VirtualKeyboardControllerAutoTest : public VirtualKeyboardControllerTest,
public VirtualKeyboardObserver {
public:
VirtualKeyboardControllerAutoTest() : notified_(false), suppressed_(false) {}
VirtualKeyboardControllerAutoTest(const VirtualKeyboardControllerAutoTest&) =
delete;
VirtualKeyboardControllerAutoTest& operator=(
const VirtualKeyboardControllerAutoTest&) = delete;
~VirtualKeyboardControllerAutoTest() override = default;
void SetUp() override {
VirtualKeyboardControllerTest::SetUp();
Shell::Get()->system_tray_notifier()->AddVirtualKeyboardObserver(this);
}
void TearDown() override {
Shell::Get()->system_tray_notifier()->RemoveVirtualKeyboardObserver(this);
VirtualKeyboardControllerTest::TearDown();
}
void OnKeyboardSuppressionChanged(bool suppressed) override {
notified_ = true;
suppressed_ = suppressed;
}
void ResetObserver() {
suppressed_ = false;
notified_ = false;
}
bool IsVirtualKeyboardSuppressed() { return suppressed_; }
bool notified() { return notified_; }
private:
bool notified_;
bool suppressed_;
};
TEST_F(VirtualKeyboardControllerAutoTest, DisabledIfInternalKeyboardPresent) {
std::vector<ui::TouchscreenDevice> screens;
screens.push_back(
ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
"Touchscreen", gfx::Size(1024, 768), 0));
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(screens);
std::vector<ui::KeyboardDevice> keyboard_devices;
keyboard_devices.push_back(ui::KeyboardDevice(
1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
ui::DeviceDataManagerTestApi().SetKeyboardDevices({});
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
}
TEST_F(VirtualKeyboardControllerAutoTest, DisabledIfNoTouchScreen) {
std::vector<ui::TouchscreenDevice> devices;
devices.push_back(
ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB,
"Touchscreen", gfx::Size(800, 600), 0));
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(devices);
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
ui::DeviceDataManagerTestApi().SetTouchscreenDevices({});
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
}
TEST_F(VirtualKeyboardControllerAutoTest, SuppressedIfExternalKeyboardPresent) {
std::vector<ui::TouchscreenDevice> screens;
screens.push_back(ui::TouchscreenDevice(
1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "Touchscreen",
gfx::Size(1024, 768), 0, false ));
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(screens);
std::vector<ui::KeyboardDevice> keyboard_devices;
keyboard_devices.push_back(
ui::KeyboardDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_TRUE(IsVirtualKeyboardSuppressed());
ResetObserver();
GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard();
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_TRUE(IsVirtualKeyboardSuppressed());
ResetObserver();
GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard();
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_TRUE(IsVirtualKeyboardSuppressed());
ResetObserver();
ui::DeviceDataManagerTestApi().SetKeyboardDevices({});
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_FALSE(IsVirtualKeyboardSuppressed());
}
TEST_F(VirtualKeyboardControllerAutoTest, HandleMultipleKeyboardsPresent) {
std::vector<ui::KeyboardDevice> keyboards;
keyboards.push_back(ui::KeyboardDevice(
1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "keyboard"));
keyboards.push_back(
ui::KeyboardDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
keyboards.push_back(
ui::KeyboardDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboards);
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
}
TEST_F(VirtualKeyboardControllerAutoTest, EnabledDuringTabletMode) {
std::vector<ui::TouchscreenDevice> screens;
screens.push_back(
ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
"Touchscreen", gfx::Size(1024, 768), 0));
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(screens);
std::vector<ui::KeyboardDevice> keyboard_devices;
keyboard_devices.push_back(ui::KeyboardDevice(
1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "Keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
}
TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInTabletMode) {
std::vector<ui::TouchscreenDevice> screens;
screens.push_back(
ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
"Touchscreen", gfx::Size(1024, 768), 0));
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(screens);
std::vector<ui::KeyboardDevice> keyboard_devices;
keyboard_devices.push_back(ui::KeyboardDevice(
1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "Keyboard"));
keyboard_devices.push_back(
ui::KeyboardDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "Keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
TabletModeControllerTestApi().EnterTabletMode();
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_TRUE(IsVirtualKeyboardSuppressed());
ResetObserver();
GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard();
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_TRUE(IsVirtualKeyboardSuppressed());
ResetObserver();
GetVirtualKeyboardController()->ToggleIgnoreExternalKeyboard();
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_TRUE(IsVirtualKeyboardSuppressed());
ResetObserver();
keyboard_devices.pop_back();
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
EXPECT_TRUE(notified());
EXPECT_FALSE(IsVirtualKeyboardSuppressed());
TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(keyboard_ui_controller()->IsEnabled());
}
class VirtualKeyboardControllerAlwaysEnabledTest
: public VirtualKeyboardControllerAutoTest {
public:
VirtualKeyboardControllerAlwaysEnabledTest()
: VirtualKeyboardControllerAutoTest() {}
VirtualKeyboardControllerAlwaysEnabledTest(
const VirtualKeyboardControllerAlwaysEnabledTest&) = delete;
VirtualKeyboardControllerAlwaysEnabledTest& operator=(
const VirtualKeyboardControllerAlwaysEnabledTest&) = delete;
~VirtualKeyboardControllerAlwaysEnabledTest() override = default;
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
keyboard::switches::kEnableVirtualKeyboard);
VirtualKeyboardControllerAutoTest::SetUp();
}
};
TEST_F(VirtualKeyboardControllerAlwaysEnabledTest, DoesNotSuppressKeyboard) {
std::vector<ui::TouchscreenDevice> screens;
screens.push_back(
ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
"Touchscreen", gfx::Size(1024, 768), 0));
ui::DeviceDataManagerTestApi().SetTouchscreenDevices(screens);
std::vector<ui::KeyboardDevice> keyboard_devices;
keyboard_devices.push_back(
ui::KeyboardDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard"));
ui::DeviceDataManagerTestApi().SetKeyboardDevices(keyboard_devices);
EXPECT_TRUE(keyboard_ui_controller()->IsEnabled());
}
}