blob: 9bd6b87eace527c6190c0a82a1e5ac19f5e7cdc0 [file] [log] [blame]
// Copyright 2021 The Fuchsia 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 <fuchsia/input/virtualkeyboard/cpp/fidl.h>
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/testing/component_context_provider.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <gtest/gtest.h>
#include <src/lib/testing/loop_fixture/test_loop_fixture.h>
#include "src/ui/bin/root_presenter/virtual_keyboard_controller.h"
#include "src/ui/bin/root_presenter/virtual_keyboard_coordinator.h"
namespace root_presenter {
namespace virtual_keyboard_fidl {
namespace {
// Tests the virtual keyboard subsystem through the FIDL interfaces exposed
// by the objects that compose the subsystem.
class VirtualKeyboardFidlTest : public gtest::TestLoopFixture {
protected:
VirtualKeyboardFidlTest() : coordinator_(context_provider_.context()) {}
template <typename Interface>
void ConnectToPublicService(fidl::InterfaceRequest<Interface> request) {
context_provider_.ConnectToPublicService(std::move(request));
}
auto CreateManagerClient() {
fuchsia::input::virtualkeyboard::ManagerPtr client;
ConnectToPublicService(client.NewRequest());
return client;
}
std::tuple<fuchsia::input::virtualkeyboard::ControllerPtr, fuchsia::ui::views::ViewRefControl>
CreateControllerClient(fuchsia::input::virtualkeyboard::TextType initial_text_type =
fuchsia::input::virtualkeyboard::TextType::ALPHANUMERIC) {
// Connect to `ControllerCreator` protocol.
fuchsia::input::virtualkeyboard::ControllerCreatorPtr controller_creator;
ConnectToPublicService(controller_creator.NewRequest());
// Create a `Controller`.
fuchsia::input::virtualkeyboard::ControllerPtr controller;
auto view_ref_pair = scenic::ViewRefPair::New();
controller_creator->Create(std::move(view_ref_pair.view_ref), initial_text_type,
controller.NewRequest());
return {std::move(controller), std::move(view_ref_pair.control_ref)};
}
private:
sys::testing::ComponentContextProvider context_provider_;
FidlBoundVirtualKeyboardCoordinator coordinator_;
};
// Tests which verify that the virtual keyboard subsystem registers the `Discoverable`
// protocols in the `fuchsia.input.virtualkeyboard` library.
namespace protocol_registration {
TEST_F(VirtualKeyboardFidlTest, RegistersControllerCreatorService) {
zx_status_t status = ZX_OK;
fuchsia::input::virtualkeyboard::ControllerCreatorPtr controller_creator;
ConnectToPublicService(controller_creator.NewRequest());
controller_creator.set_error_handler([&status](zx_status_t stat) { status = stat; });
fuchsia::input::virtualkeyboard::ControllerPtr controller;
auto view_ref_pair = scenic::ViewRefPair::New();
controller_creator->Create(std::move(view_ref_pair.view_ref),
fuchsia::input::virtualkeyboard::TextType::ALPHANUMERIC,
controller.NewRequest());
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
}
TEST_F(VirtualKeyboardFidlTest, RegistersManagerService) {
zx_status_t status = ZX_OK;
auto manager = CreateManagerClient();
ConnectToPublicService(manager.NewRequest());
manager.set_error_handler([&status](zx_status_t stat) { status = stat; });
manager->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
}
} // namespace protocol_registration
// Tests which validate how connections to `fuchsia.input.virtualkeyboard.Controller` are handled.
namespace fuchsia_input_virtualkeyboard_controller_connections {
TEST_F(VirtualKeyboardFidlTest, ClosingCreatorDoesNotCloseController) {
// Note: this test creates the controller manually (instead of using CreateControllerClient()),
// because this test
// a) wants to set an error handler on the ControllerCreator
// b) wants to be explicit about the lifetime of the ControllerCreator
// Connect to `ControllerCreator` protocol.
fuchsia::input::virtualkeyboard::ControllerCreatorPtr controller_creator;
ConnectToPublicService(controller_creator.NewRequest());
// Create controller.
zx_status_t controller_status = ZX_OK;
fuchsia::input::virtualkeyboard::ControllerPtr controller;
auto view_ref_pair1 = scenic::ViewRefPair::New();
controller_creator->Create(std::move(view_ref_pair1.view_ref),
fuchsia::input::virtualkeyboard::TextType::ALPHANUMERIC,
controller.NewRequest());
controller.set_error_handler(
[&controller_status](zx_status_t stat) { controller_status = stat; });
RunLoopUntilIdle();
// Close the `ControllerCreator` connection.
controller_creator.Unbind();
RunLoopUntilIdle();
// Call a method on the `Controller`, and verify no error occurred.
controller->RequestShow();
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, controller_status) << "status = " << zx_status_get_string(controller_status);
}
TEST_F(VirtualKeyboardFidlTest, MultipleControllersAreSupported) {
// Create first controller.
zx_status_t controller1_status = ZX_OK;
auto [controller1, view_ref_control1] = CreateControllerClient();
controller1.set_error_handler(
[&controller1_status](zx_status_t stat) { controller1_status = stat; });
RunLoopUntilIdle();
// Create second controller.
zx_status_t controller2_status = ZX_OK;
auto [controller2, view_ref_control2] = CreateControllerClient();
controller2.set_error_handler(
[&controller2_status](zx_status_t stat) { controller2_status = stat; });
RunLoopUntilIdle();
// Verify that te first controller can invoke a method.
controller1->RequestShow();
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, controller1_status) << "status = " << zx_status_get_string(controller1_status);
// Verify that the second controller can invoke a method.
controller2->RequestHide();
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, controller2_status) << "status = " << zx_status_get_string(controller2_status);
}
} // namespace fuchsia_input_virtualkeyboard_controller_connections
// Tests that verify the behavior of the methods of `fuchsia.input.virtualkeyboard.Controller`.
//
// Note: these tests focus on the values/errors returned by Controller methods, _not_ how these
// methods affect values returned to calls on other protocols.
//
// To see, for example, how Controller.RequestShow() resolves a hanging get call to
// Manager.WatchtypeAndVisibility(), see the fuchsia_input_virtualkeyboard_manager_methods
// tests.
namespace fuchsia_input_virtualkeyboard_controller_methods {
TEST_F(VirtualKeyboardFidlTest, SetTextTypeDoesNotError) {
// Create controller.
zx_status_t controller_status = ZX_OK;
auto [controller, view_ref_control] = CreateControllerClient();
controller.set_error_handler(
[&controller_status](zx_status_t stat) { controller_status = stat; });
// Invoke SetTextType(), and verify there is no error on the channel.
controller->SetTextType(fuchsia::input::virtualkeyboard::TextType::PHONE);
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, controller_status) << "status = " << zx_status_get_string(controller_status);
}
TEST_F(VirtualKeyboardFidlTest, RequestShowDoesNotError) {
// Create controller.
zx_status_t controller_status = ZX_OK;
auto [controller, view_ref_control] = CreateControllerClient();
controller.set_error_handler(
[&controller_status](zx_status_t stat) { controller_status = stat; });
// Invoke RequestShow(), and verify there is no error on the channel.
controller->RequestShow();
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, controller_status) << "status = " << zx_status_get_string(controller_status);
}
TEST_F(VirtualKeyboardFidlTest, RequestHideDoesNotError) {
// Create controller.
zx_status_t controller_status = ZX_OK;
auto [controller, view_ref_control] = CreateControllerClient();
controller.set_error_handler(
[&controller_status](zx_status_t stat) { controller_status = stat; });
// Invoke RequestHide(), and verify there is no error on the channel.
controller->RequestHide();
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, controller_status) << "status = " << zx_status_get_string(controller_status);
}
TEST_F(VirtualKeyboardFidlTest, WatchVisibility_FirstCallReturnsImmediately) {
// Create controller.
auto [controller, view_ref_control] = CreateControllerClient();
// Send watch.
bool got_watch_visibility_result = false;
controller->WatchVisibility(
[&got_watch_visibility_result](bool vis) { got_watch_visibility_result = true; });
RunLoopUntilIdle();
// Verify watch completed immediately.
ASSERT_TRUE(got_watch_visibility_result);
}
TEST_F(VirtualKeyboardFidlTest, WatchVisibility_SecondCallHangs) {
// Create controller.
zx_status_t controller_status = ZX_OK;
auto [controller, view_ref_control] = CreateControllerClient();
controller.set_error_handler(
[&controller_status](zx_status_t stat) { controller_status = stat; });
// Send first watch, which completes immediately.
controller->WatchVisibility([](bool vis) {});
RunLoopUntilIdle();
// Send second watch, which hangs.
bool got_watch_visibility_result = false;
controller->WatchVisibility(
[&got_watch_visibility_result](bool vis) { got_watch_visibility_result = true; });
RunLoopUntilIdle();
ASSERT_FALSE(got_watch_visibility_result);
ASSERT_EQ(ZX_OK, controller_status) << "status = " << zx_status_get_string(controller_status);
}
TEST_F(VirtualKeyboardFidlTest, WatchVisibility_SecondCallIsResolvedByOwnRequestShow) {
// Create controller.
auto [controller, view_ref_control] = CreateControllerClient();
// Send first watch, which completes immediately.
controller->WatchVisibility([](bool vis) {});
RunLoopUntilIdle();
// Second second watch, and let it hang.
bool got_watch_visibility_result = false;
controller->WatchVisibility(
[&got_watch_visibility_result](bool vis) { got_watch_visibility_result = true; });
RunLoopUntilIdle();
// Request the keyboard to be shown. This changes the state of the keyboard, since
// the default state is hidden.
controller->RequestShow();
RunLoopUntilIdle();
// Verify that the watch completed.
//
// Note: when we incorporate focus state into VirtualKeyboardCoordinator, we'll need
// to update this test. (The watch should not complete until the `View` associated with
// `view_ref_pair` has focus.)
ASSERT_TRUE(got_watch_visibility_result);
}
TEST_F(VirtualKeyboardFidlTest, WatchVisibility_SecondCallIsNotResolvedByOwnRequestHide) {
// Create controller.
zx_status_t controller_status = ZX_OK;
auto [controller, view_ref_control] = CreateControllerClient();
controller.set_error_handler(
[&controller_status](zx_status_t stat) { controller_status = stat; });
// Send first watch, which completes immediately.
controller->WatchVisibility([](bool vis) {});
RunLoopUntilIdle();
// Second second watch, and let it hang.
bool got_watch_visibility_result = false;
controller->WatchVisibility(
[&got_watch_visibility_result](bool vis) { got_watch_visibility_result = true; });
RunLoopUntilIdle();
// Request the keyboard to be hidden. This does _not_ change the state of the keyboard,
// since the default state is also hidden.
controller->RequestHide();
RunLoopUntilIdle();
// Verify that the watch did not complete.
ASSERT_FALSE(got_watch_visibility_result);
ASSERT_EQ(ZX_OK, controller_status) << "status = " << zx_status_get_string(controller_status);
}
TEST_F(VirtualKeyboardFidlTest,
WatchVisibility_SecondCallIsResolvedByManagerReportOfUserInteraction) {
// Create controller.
auto [controller, view_ref_control] = CreateControllerClient();
// Send first watch, which completes immediately.
controller->WatchVisibility([](bool vis) {});
RunLoopUntilIdle();
// Second second watch, and let it hang.
bool got_watch_visibility_result = false;
controller->WatchVisibility(
[&got_watch_visibility_result](bool vis) { got_watch_visibility_result = true; });
RunLoopUntilIdle();
// Create Manager, and call Notify().
auto manager = CreateManagerClient();
manager->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
RunLoopUntilIdle();
// Verify that the watch completed.
ASSERT_TRUE(got_watch_visibility_result);
}
TEST_F(VirtualKeyboardFidlTest, WatchVisibility_AllControllersAreToldOfUserInteraction) {
// Create controller.
auto [controller1, view_ref_control1] = CreateControllerClient();
auto [controller2, view_ref_control2] = CreateControllerClient();
// Send first watch for each controller, which completes immediately.
controller1->WatchVisibility([](bool vis) {});
controller2->WatchVisibility([](bool vis) {});
RunLoopUntilIdle();
// Second second watch on each controller, and let them hang.
bool c1_got_watch_visibility_result = false;
bool c2_got_watch_visibility_result = false;
controller1->WatchVisibility([&](bool vis) { c1_got_watch_visibility_result = true; });
controller2->WatchVisibility([&](bool vis) { c2_got_watch_visibility_result = true; });
RunLoopUntilIdle();
// Create Manager, and call Notify().
auto manager = CreateManagerClient();
manager->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
RunLoopUntilIdle();
// Verify that the watch completed.
ASSERT_TRUE(c1_got_watch_visibility_result);
ASSERT_TRUE(c2_got_watch_visibility_result);
}
} // namespace fuchsia_input_virtualkeyboard_controller_methods
// Tests which validate how connections to `fuchsia.input.virtualkeyboard.Manager` are handled.
namespace fuchsia_input_virtualkeyboard_manager_connections {
TEST_F(VirtualKeyboardFidlTest, FirstManagerClientHasPriority) {
// First client tries to connect.
zx_status_t client1_status = ZX_OK;
auto client1 = CreateManagerClient();
client1.set_error_handler([&client1_status](zx_status_t stat) { client1_status = stat; });
RunLoopUntilIdle();
// Second client tries to connect.
zx_status_t client2_status = ZX_OK;
auto client2 = CreateManagerClient();
client2.set_error_handler([&client2_status](zx_status_t stat) { client2_status = stat; });
RunLoopUntilIdle();
// Both clients try to call `Notify()`.
client1->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
client2->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
ASSERT_EQ(ZX_OK, client1_status) << "status = " << zx_status_get_string(client1_status);
ASSERT_NE(ZX_OK, client2_status) << "status = " << zx_status_get_string(client2_status);
}
TEST_F(VirtualKeyboardFidlTest, NewManagerClientCanConnectAndNotifyAfterFirstDisconnects) {
{
// First client connects and calls Notify().
zx_status_t status = ZX_OK;
auto client = CreateManagerClient();
client.set_error_handler([&status](zx_status_t stat) { status = stat; });
client->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
}
// Run event loop, to process side-effects of `client` going away.
RunLoopUntilIdle();
{
// Second client connects and calls Notify().
zx_status_t status = ZX_OK;
auto client = CreateManagerClient();
client.set_error_handler([&status](zx_status_t stat) { status = stat; });
client->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
}
}
TEST_F(VirtualKeyboardFidlTest, NewManagerClientCanConnectAndWatchAfterFirstDisconnects) {
{
// Create first Manager client, and have the client call WatchTypeAndVisibility().
zx_status_t status = ZX_OK;
auto client = CreateManagerClient();
bool did_watch_complete = false;
client.set_error_handler([&status](zx_status_t stat) { status = stat; });
client->WatchTypeAndVisibility([&did_watch_complete](fuchsia::input::virtualkeyboard::TextType,
bool) { did_watch_complete = true; });
// Manager client connection should be ok, and the client's WatchTypeAndVisibility() call
// should have returned.
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
ASSERT_TRUE(did_watch_complete);
}
// Run event loop, to process side-effects of `client` going away.
RunLoopUntilIdle();
{
// Create second Manager client, and have the client call WatchTypeAndVisibility().
zx_status_t status = ZX_OK;
auto client = CreateManagerClient();
bool did_watch_complete = false;
client.set_error_handler([&status](zx_status_t stat) { status = stat; });
client->WatchTypeAndVisibility([&did_watch_complete](fuchsia::input::virtualkeyboard::TextType,
bool) { did_watch_complete = true; });
// Manager client connection should be ok, and the client's WatchTypeAndVisibility() call
// should have returned.
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
ASSERT_TRUE(did_watch_complete);
}
}
TEST_F(VirtualKeyboardFidlTest, ManagerDisconnectsOnConcurrentWatches) {
// Connect client.
zx_status_t status = ZX_OK;
auto client = CreateManagerClient();
client.set_error_handler([&status](zx_status_t stat) { status = stat; });
// Send first watch, which completes immediately.
client->WatchTypeAndVisibility([](fuchsia::input::virtualkeyboard::TextType, bool) {});
RunLoopUntilIdle();
// Now, set up two concurrent watches.
client->WatchTypeAndVisibility([](fuchsia::input::virtualkeyboard::TextType, bool) {});
client->WatchTypeAndVisibility([](fuchsia::input::virtualkeyboard::TextType, bool) {});
RunLoopUntilIdle();
// Verify that the channel was closed, with the expected epitaph.
ASSERT_EQ(ZX_ERR_BAD_STATE, status) << "status = " << zx_status_get_string(status);
}
TEST_F(VirtualKeyboardFidlTest, ClientDisconnectionNotifiesControllersThatKeyboardIsHidden) {
// Create controller, and set visibility to true.
auto [controller, view_ref_control] = CreateControllerClient();
controller->RequestShow();
RunLoopUntilIdle();
// Send a watch request, which will complete immediately.
std::optional<bool> first_watcher_visibility;
controller->WatchVisibility(
[&first_watcher_visibility](bool vis) { first_watcher_visibility = vis; });
RunLoopUntilIdle();
ASSERT_EQ(true, first_watcher_visibility);
// Create manager.
std::optional<fuchsia::input::virtualkeyboard::ManagerPtr> manager = CreateManagerClient();
// Set up a watch.
std::optional<bool> second_visibility_result;
controller->WatchVisibility(
[&second_visibility_result](bool vis) { second_visibility_result = vis; });
RunLoopUntilIdle();
// Disconnect the maanger.
manager.reset();
RunLoopUntilIdle();
// Verify that the controller learned that the keyboard was hidden.
ASSERT_EQ(false, second_visibility_result);
}
TEST_F(VirtualKeyboardFidlTest, NewManagerClientCanConnectAfterFirstIsDisconnectedByError) {
// Connect client, and set up concurrent watches.
auto client1 = CreateManagerClient();
// Send first watch, which completes immediately.
client1->WatchTypeAndVisibility([](fuchsia::input::virtualkeyboard::TextType, bool) {});
RunLoopUntilIdle();
// Set up two concurrent watches, to force closure of client1.
client1->WatchTypeAndVisibility([](fuchsia::input::virtualkeyboard::TextType, bool) {});
client1->WatchTypeAndVisibility([](fuchsia::input::virtualkeyboard::TextType, bool) {});
RunLoopUntilIdle();
// Second client connects and calls Notify().
zx_status_t status = ZX_OK;
auto client2 = CreateManagerClient();
client2.set_error_handler([&status](zx_status_t stat) { status = stat; });
client2->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[]() {});
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
}
} // namespace fuchsia_input_virtualkeyboard_manager_connections
// Tests that verify the behavior of the methods of `fuchsia.input.virtualkeyboard.Manager`.
//
// Note: these tests focus on the values/errors returned by Manager methods, _not_ how these
// methods affect values returned to calls on other protocols.
//
// To see, for example, how Manager.Notify() resolves a hanging get call to
// Controller.WatchVisibility(), see the fuchsia_input_virtualkeyboard_controller_methods
// tests.
namespace fuchsia_input_virtualkeyboard_manager_methods {
TEST_F(VirtualKeyboardFidlTest, WatchTypeAndVisibility_FirstCallReturnsImmediately) {
auto manager = CreateManagerClient();
bool was_called = false;
manager->WatchTypeAndVisibility([&](fuchsia::input::virtualkeyboard::TextType reason,
bool is_visible) { was_called = true; });
RunLoopUntilIdle();
ASSERT_TRUE(was_called);
}
TEST_F(VirtualKeyboardFidlTest, WatchTypeAndVisibility_SecondCallHangs) {
// Create manager.
zx_status_t manager_status = ZX_OK;
auto manager = CreateManagerClient();
manager.set_error_handler([&](zx_status_t stat) { manager_status = stat; });
// Send first watch, which completes immediately.
manager->WatchTypeAndVisibility(
[](fuchsia::input::virtualkeyboard::TextType reason, bool is_visible) {});
// Send second watch, which hangs.
bool was_called = false;
manager->WatchTypeAndVisibility([&](fuchsia::input::virtualkeyboard::TextType reason,
bool is_visible) { was_called = true; });
RunLoopUntilIdle();
ASSERT_FALSE(was_called);
ASSERT_EQ(ZX_OK, manager_status) << "status = " << zx_status_get_string(manager_status);
}
TEST_F(VirtualKeyboardFidlTest, WatchTypeAndVisibility_SecondCallIsResolvedByRequestShow) {
// Create manager.
auto manager = CreateManagerClient();
// Send first watch, which completes immediately.
manager->WatchTypeAndVisibility(
[](fuchsia::input::virtualkeyboard::TextType reason, bool is_visible) {});
// Send second watch, which hangs.
bool was_called = false;
manager->WatchTypeAndVisibility([&](fuchsia::input::virtualkeyboard::TextType reason,
bool is_visible) { was_called = true; });
RunLoopUntilIdle();
// Create a Controller, and ask for the keyboard to be shown. This changes the state of
// the keyboard, since the default state is hidden.
auto [controller, view_ref_control] = CreateControllerClient();
controller->RequestShow();
RunLoopUntilIdle();
ASSERT_TRUE(was_called);
}
TEST_F(VirtualKeyboardFidlTest, WatchTypeAndVisibility_SecondCallIsNotResolvedByRequestHide) {
// Create manager.
zx_status_t manager_status = ZX_OK;
auto manager = CreateManagerClient();
manager.set_error_handler([&](zx_status_t stat) { manager_status = stat; });
// Send first watch, which completes immediately.
manager->WatchTypeAndVisibility(
[](fuchsia::input::virtualkeyboard::TextType reason, bool is_visible) {});
// Send second watch, which hangs.
bool was_called = false;
manager->WatchTypeAndVisibility([&](fuchsia::input::virtualkeyboard::TextType reason,
bool is_visible) { was_called = true; });
RunLoopUntilIdle();
// Create a Controller, and ask for the keyboard to be hidden. This does _not_ change the
// state of the keyboard, since the default state is also hidden.
auto [controller, view_ref_control] = CreateControllerClient();
controller->RequestHide();
RunLoopUntilIdle();
ASSERT_FALSE(was_called);
ASSERT_EQ(ZX_OK, manager_status) << "status = " << zx_status_get_string(manager_status);
}
TEST_F(VirtualKeyboardFidlTest, WatchTypeAndVisibility_SecondCallIsResolvedBySetTextType) {
// Create manager.
auto manager = CreateManagerClient();
// Send first watch, which completes immediately.
manager->WatchTypeAndVisibility(
[](fuchsia::input::virtualkeyboard::TextType reason, bool is_visible) {});
// Send second watch, which hangs.
bool was_called = false;
manager->WatchTypeAndVisibility([&](fuchsia::input::virtualkeyboard::TextType reason,
bool is_visible) { was_called = true; });
RunLoopUntilIdle();
// Create a Controller, then change the text type.
auto [controller, view_ref_control] =
CreateControllerClient(fuchsia::input::virtualkeyboard::TextType::NUMERIC);
controller->SetTextType(fuchsia::input::virtualkeyboard::TextType::PHONE);
RunLoopUntilIdle();
ASSERT_TRUE(was_called);
}
TEST_F(VirtualKeyboardFidlTest, WatchTypeAndVisibility_ReceivesConfigSetBeforeManagerConnection) {
// Create a Controller, and request that the keyboard be shown.
auto [controller, view_ref_control] =
CreateControllerClient(fuchsia::input::virtualkeyboard::TextType::NUMERIC);
controller->RequestShow();
RunLoopUntilIdle();
// Create manager.
auto manager = CreateManagerClient();
// Try to get the visibility of the keyboard.
std::optional<bool> is_visible;
manager->WatchTypeAndVisibility(
[&](fuchsia::input::virtualkeyboard::TextType reason, bool is_vis) { is_visible = is_vis; });
RunLoopUntilIdle();
ASSERT_EQ(true, is_visible);
}
TEST_F(VirtualKeyboardFidlTest,
WatchTypeAndVisibility_SecondNewManagerDoesNotReceiveBufferedConfig) {
// Create a Controller, and request that the keyboard be shown.
auto [controller, view_ref_control] =
CreateControllerClient(fuchsia::input::virtualkeyboard::TextType::NUMERIC);
controller->RequestShow();
RunLoopUntilIdle();
{
// Create first manager.
auto manager = CreateManagerClient();
// Get configuration.
manager->WatchTypeAndVisibility(
[](fuchsia::input::virtualkeyboard::TextType type, bool is_vis) {});
RunLoopUntilIdle();
}
{
// Create second manager.
auto manager = CreateManagerClient();
// Get configuration.
std::optional<fuchsia::input::virtualkeyboard::TextType> text_type;
manager->WatchTypeAndVisibility(
[&](fuchsia::input::virtualkeyboard::TextType type, bool is_vis) { text_type = type; });
RunLoopUntilIdle();
ASSERT_NE(fuchsia::input::virtualkeyboard::TextType::NUMERIC, text_type);
}
}
TEST_F(VirtualKeyboardFidlTest,
WatchTypeAndVisibility_GetsCorrectVisibilityAfterRaceOnProgrammaticChangeNotification) {
// Create controller and manager.
auto [controller, view_ref_control] =
CreateControllerClient(fuchsia::input::virtualkeyboard::TextType::NUMERIC);
auto manager = CreateManagerClient();
// Request the keyboard to be hidden.
controller->RequestHide();
RunLoopUntilIdle();
// Request the keyboard to be shown.
controller->RequestShow();
RunLoopUntilIdle();
// Echo back the first request. We deliberately send this _after_ the RequestShow() above.
manager->Notify(false, fuchsia::input::virtualkeyboard::VisibilityChangeReason::PROGRAMMATIC,
[]() {});
RunLoopUntilIdle();
// Modify the text type.
controller->SetTextType(::fuchsia::input::virtualkeyboard::TextType::PHONE);
RunLoopUntilIdle();
// Verify that the keyboard is still shown.
std::optional<bool> actual_visibility;
manager->WatchTypeAndVisibility([&](fuchsia::input::virtualkeyboard::TextType reason,
bool is_visible) { actual_visibility = is_visible; });
RunLoopUntilIdle();
ASSERT_EQ(true, actual_visibility);
}
TEST_F(VirtualKeyboardFidlTest, NotifyIsAcked) {
bool got_ack = false;
zx_status_t status = ZX_OK;
auto manager = CreateManagerClient();
manager.set_error_handler([&status](zx_status_t stat) { status = stat; });
manager->Notify(true, fuchsia::input::virtualkeyboard::VisibilityChangeReason::USER_INTERACTION,
[&got_ack]() { got_ack = true; });
RunLoopUntilIdle();
ASSERT_EQ(ZX_OK, status) << "status = " << zx_status_get_string(status);
ASSERT_EQ(true, got_ack);
}
} // namespace fuchsia_input_virtualkeyboard_manager_methods
} // namespace
} // namespace virtual_keyboard_fidl
} // namespace root_presenter