Flutter Engine
The Flutter Engine
text-input-test.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fuchsia/feedback/cpp/fidl.h>
6#include <fuchsia/logger/cpp/fidl.h>
7#include <fuchsia/sysmem/cpp/fidl.h>
8#include <fuchsia/tracing/provider/cpp/fidl.h>
9#include <fuchsia/ui/app/cpp/fidl.h>
10#include <fuchsia/ui/display/singleton/cpp/fidl.h>
11#include <fuchsia/ui/input/cpp/fidl.h>
12#include <fuchsia/ui/test/input/cpp/fidl.h>
13#include <fuchsia/ui/test/scene/cpp/fidl.h>
14#include <lib/async-loop/testing/cpp/real_loop.h>
15#include <lib/async/cpp/task.h>
16#include <lib/fidl/cpp/binding_set.h>
17#include <lib/sys/component/cpp/testing/realm_builder.h>
18#include <lib/sys/component/cpp/testing/realm_builder_types.h>
19#include <lib/zx/clock.h>
20#include <lib/zx/time.h>
21#include <zircon/status.h>
22#include <zircon/types.h>
23#include <zircon/utc.h>
24
25#include <cstddef>
26#include <cstdint>
27#include <iostream>
28#include <memory>
29#include <type_traits>
30#include <utility>
31#include <vector>
32
33#include <gtest/gtest.h>
34
35#include "flutter/fml/logging.h"
36#include "flutter/shell/platform/fuchsia/flutter/tests/integration/utils/check_view.h"
37#include "flutter/shell/platform/fuchsia/flutter/tests/integration/utils/portable_ui_test.h"
38
39namespace {
40
41// Types imported for the realm_builder library.
42using component_testing::ChildRef;
43using component_testing::LocalComponentImpl;
44using component_testing::ParentRef;
45using component_testing::Protocol;
46using component_testing::RealmBuilder;
47using component_testing::RealmRoot;
48using component_testing::Route;
49
52
53/// Max timeout in failure cases.
54/// Set this as low as you can that still works across all test platforms.
55constexpr zx::duration kTimeout = zx::min(5);
56
57constexpr auto kKeyboardInputListener = "keyboard_input_listener";
58constexpr auto kKeyboardInputListenerRef = ChildRef{kKeyboardInputListener};
59
60constexpr auto kTextInputView = "text-input-view";
61constexpr auto kTextInputViewRef = ChildRef{kTextInputView};
62static constexpr auto kTextInputViewUrl =
63 "fuchsia-pkg://fuchsia.com/text-input-view#meta/text-input-view.cm";
64
65constexpr auto kTestUIStackUrl =
66 "fuchsia-pkg://fuchsia.com/flatland-scene-manager-test-ui-stack#meta/"
67 "test-ui-stack.cm";
68
69/// |KeyboardInputListener| is a local test protocol that our test Flutter app
70/// uses to let us know what text is being entered into its only text field.
71///
72/// The text field contents are reported on almost every change, so if you are
73/// entering a long text, you will see calls corresponding to successive
74/// additions of characters, not just the end result.
75class KeyboardInputListenerServer
76 : public fuchsia::ui::test::input::KeyboardInputListener,
77 public LocalComponentImpl {
78 public:
79 explicit KeyboardInputListenerServer(async_dispatcher_t* dispatcher)
80 : dispatcher_(dispatcher) {}
81
82 // |fuchsia::ui::test::input::KeyboardInputListener|
83 void ReportTextInput(
84 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
85 request) override {
86 FML_LOG(INFO) << "Flutter app sent: '" << request.text() << "'";
87 response_list_.push_back(request.text());
88 }
89
90 /// Starts this server.
91 void OnStart() override {
92 FML_LOG(INFO) << "Starting KeyboardInputListenerServer";
93 ASSERT_EQ(ZX_OK, outgoing()->AddPublicService(
94 bindings_.GetHandler(this, dispatcher_)));
95 }
96
97 /// Returns true if the response vector values matches `expected`
98 bool HasResponse(const std::vector<std::string>& expected) {
99 if (response_list_.size() != expected.size()) {
100 return false;
101 }
102
103 // Iterate through the expected vector
104 // Corresponding indices for response_list and expected should contain the
105 // same values
106 for (size_t i = 0; i < expected.size(); ++i) {
107 if (response_list_[i] != expected[i]) {
108 return false;
109 }
110 }
111
112 return true;
113 }
114
115 // KeyboardInputListener override
116 void ReportReady(ReportReadyCallback callback) override {
117 FML_LOG(INFO) << "ReportReady callback ready";
118 ready_ = true;
119 callback();
120 }
121
122 private:
123 async_dispatcher_t* dispatcher_ = nullptr;
124 fidl::BindingSet<fuchsia::ui::test::input::KeyboardInputListener> bindings_;
125 std::vector<std::string> response_list_;
126 bool ready_ = false;
127};
128
129class TextInputTest : public PortableUITest,
130 public ::testing::Test,
131 public ::testing::WithParamInterface<std::string> {
132 protected:
133 void SetUp() override {
134 PortableUITest::SetUp();
135
136 // Post a "just in case" quit task, if the test hangs.
137 async::PostDelayedTask(
138 dispatcher(),
139 [] {
141 << "\n\n>> Test did not complete in time, terminating. <<\n\n";
142 },
143 kTimeout);
144
145 // Get the display dimensions.
146 FML_LOG(INFO)
147 << "Waiting for display info from fuchsia.ui.display.singleton.Info";
148 fuchsia::ui::display::singleton::InfoPtr display_info =
149 realm_root()
150 ->component()
151 .Connect<fuchsia::ui::display::singleton::Info>();
152 display_info->GetMetrics(
153 [this](fuchsia::ui::display::singleton::Metrics metrics) {
154 display_width_ = metrics.extent_in_px().width;
155 display_height_ = metrics.extent_in_px().height;
156 FML_LOG(INFO) << "Got display_width = " << display_width_
157 << " and display_height = " << display_height_;
158 });
159 RunLoopUntil(
160 [this] { return display_width_ != 0 && display_height_ != 0; });
161
162 // Register input injection device.
163 FML_LOG(INFO) << "Registering input injection device";
164 RegisterKeyboard();
165 }
166
167 // Guaranteed to be initialized after SetUp().
168 uint32_t display_width() const { return display_width_; }
169 uint32_t display_height() const { return display_height_; }
170
171 std::string GetTestUIStackUrl() override { return GetParam(); };
172
173 KeyboardInputListenerServer* keyboard_input_listener_server_;
174
175 private:
176 void ExtendRealm() override {
177 FML_LOG(INFO) << "Extending realm";
178 // Key part of service setup: have this test component vend the
179 // |KeyboardInputListener| service in the constructed realm.
180 auto keyboard_input_listener_server =
181 std::make_unique<KeyboardInputListenerServer>(dispatcher());
182 keyboard_input_listener_server_ = keyboard_input_listener_server.get();
183 realm_builder()->AddLocalChild(
184 kKeyboardInputListener,
185 [keyboard_input_listener_server =
186 std::move(keyboard_input_listener_server)]() mutable {
187 return std::move(keyboard_input_listener_server);
188 });
189
190 // Add text-input-view to the Realm
191 realm_builder()->AddChild(kTextInputView, kTextInputViewUrl,
192 component_testing::ChildOptions{
193 .environment = kFlutterRunnerEnvironment,
194 });
195
196 // Route KeyboardInputListener to the runner and Flutter app
197 realm_builder()->AddRoute(
198 Route{.capabilities = {Protocol{
199 fuchsia::ui::test::input::KeyboardInputListener::Name_}},
200 .source = kKeyboardInputListenerRef,
201 .targets = {kFlutterJitRunnerRef, kTextInputViewRef}});
202
203 // Expose fuchsia.ui.app.ViewProvider from the flutter app.
204 realm_builder()->AddRoute(
205 Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
206 .source = kTextInputViewRef,
207 .targets = {ParentRef()}});
208
209 realm_builder()->AddRoute(Route{
210 .capabilities =
211 {Protocol{fuchsia::ui::input3::Keyboard::Name_},
212 Protocol{"fuchsia.accessibility.semantics.SemanticsManager"}},
213 .source = kTestUIStackRef,
214 .targets = {ParentRef(), kFlutterJitRunnerRef}});
215 }
216};
217
218INSTANTIATE_TEST_SUITE_P(TextInputTestParameterized,
219 TextInputTest,
220 ::testing::Values(kTestUIStackUrl));
221
222TEST_P(TextInputTest, TextInput) {
223 // Launch view
224 FML_LOG(INFO) << "Initializing scene";
225 LaunchClient();
226 FML_LOG(INFO) << "Client launched";
227
228 SimulateTextEntry("Hello\nworld!");
229 std::vector<std::string> expected = {"LEFT_SHIFT", "H", "E", "L", "L", "O",
230 "ENTER", "W", "O", "R", "L", "D",
231 "LEFT_SHIFT", "KEY_1"};
232
233 RunLoopUntil(
234 [&] { return keyboard_input_listener_server_->HasResponse(expected); });
235}
236
237} // namespace
double duration
Definition: examples.cpp:30
#define FATAL(error)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_LOG(severity)
Definition: logging.h:82
static float min(float r, float g, float b)
Definition: hsl.cpp:48
INSTANTIATE_TEST_SUITE_P(EmbedderTestGlVk, EmbedderTestMultiBackend, ::testing::Values(EmbedderTestContextType::kOpenGLContext, EmbedderTestContextType::kVulkanContext))
bool CheckViewExistsInUpdates(const std::vector< fuchsia::ui::observation::geometry::ViewTreeSnapshot > &updates, zx_koid_t view_ref_koid)
Definition: check_view.cc:27
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)