Mir

Merge lp:~robertcarr/mir/refactor-input-acceptance-take-1 into lp:mir

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~robertcarr/mir/refactor-input-acceptance-take-1
Merge into: lp:mir
Diff against target: 1600 lines (+720/-471)
17 files modified
doc/component_reports.md (+1/-0)
include/shared/mir/input/input_platform.h (+3/-1)
include/shared/mir/input/input_receiver_report.h (+48/-0)
include/shared/mir/input/null_input_receiver_report.h (+46/-0)
include/test/mir_test_framework/input_testing_server_configuration.h (+2/-1)
src/client/CMakeLists.txt (+1/-0)
src/client/default_connection_configuration.cpp (+20/-2)
src/client/default_connection_configuration.h (+9/-0)
src/client/logging/input_receiver_report.cpp (+125/-0)
src/client/logging/input_receiver_report.h (+54/-0)
src/shared/input/android/android_input_platform.cpp (+11/-3)
src/shared/input/android/android_input_platform.h (+4/-1)
src/shared/input/android/android_input_receiver.cpp (+9/-2)
src/shared/input/android/android_input_receiver.h (+7/-2)
tests/acceptance-tests/test_client_input.cpp (+367/-452)
tests/unit-tests/client/input/test_android_input_receiver.cpp (+8/-5)
tests/unit-tests/client/input/test_android_input_receiver_thread.cpp (+5/-2)
To merge this branch: bzr merge lp:~robertcarr/mir/refactor-input-acceptance-take-1
Reviewer Review Type Date Requested Status
Mir development team Pending
Review via email: mp+194264@code.launchpad.net

This proposal has been superseded by a proposal from 2013-11-07.

Commit message

Simplify input acceptance tests with a better shared fixture.

Description of the change

First take at simplifying input acceptance tests with a better shared fixture.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/component_reports.md'
2--- doc/component_reports.md 2013-10-24 11:41:30 +0000
3+++ doc/component_reports.md 2013-11-07 00:22:14 +0000
4@@ -40,6 +40,7 @@
5 Report | Handlers
6 ------------------- | --------
7 rpc-report | log,lttng
8+input-receiver | log
9
10 For example, to enable the logging RPC report, one should set the
11 `MIR_CLIENT_RPC_REPORT=log` environment variable.
12
13=== modified file 'include/shared/mir/input/input_platform.h'
14--- include/shared/mir/input/input_platform.h 2013-05-13 23:20:52 +0000
15+++ include/shared/mir/input/input_platform.h 2013-11-07 00:22:14 +0000
16@@ -31,6 +31,7 @@
17 namespace receiver
18 {
19 class InputReceiverThread;
20+class InputReceiverReport;
21
22 // Interface for MirSurface to construct input dispatcher threads.
23 class InputPlatform
24@@ -39,8 +40,9 @@
25 virtual ~InputPlatform() {};
26
27 virtual std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback) = 0;
28-
29+
30 static std::shared_ptr<InputPlatform> create();
31+ static std::shared_ptr<InputPlatform> create(std::shared_ptr<InputReceiverReport> const& report);
32
33 protected:
34 InputPlatform() = default;
35
36=== added file 'include/shared/mir/input/input_receiver_report.h'
37--- include/shared/mir/input/input_receiver_report.h 1970-01-01 00:00:00 +0000
38+++ include/shared/mir/input/input_receiver_report.h 2013-11-07 00:22:14 +0000
39@@ -0,0 +1,48 @@
40+/*
41+ * Copyright © 2013 Canonical Ltd.
42+ *
43+ * This program is free software: you can redistribute it and/or modify
44+ * it under the terms of the GNU Lesser General Public License version 3 as
45+ * published by the Free Software Foundation.
46+ *
47+ * This program is distributed in the hope that it will be useful,
48+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
49+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50+ * GNU Lesser General Public License for more details.
51+ *
52+ * You should have received a copy of the GNU Lesser General Public License
53+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
54+ *
55+ * Authored by: Robert Carr <robert.carr@canonical.com>
56+ */
57+
58+#ifndef MIR_CLIENT_INPUT_RECEIVER_REPORT_H_
59+#define MIR_CLIENT_INPUT_RECEIVER_REPORT_H_
60+
61+#include <mir_toolkit/event.h>
62+
63+namespace mir
64+{
65+namespace input
66+{
67+namespace receiver
68+{
69+
70+class InputReceiverReport
71+{
72+public:
73+ virtual ~InputReceiverReport() = default;
74+
75+ virtual void received_event(MirEvent const& event) = 0;
76+
77+protected:
78+ InputReceiverReport() = default;
79+ InputReceiverReport(InputReceiverReport const&) = delete;
80+ InputReceiverReport& operator=(InputReceiverReport const&) = delete;
81+};
82+
83+}
84+}
85+}
86+
87+#endif /* MIR_CLIENT_INPUT_RECEIVER_REPORT_H_ */
88
89=== added file 'include/shared/mir/input/null_input_receiver_report.h'
90--- include/shared/mir/input/null_input_receiver_report.h 1970-01-01 00:00:00 +0000
91+++ include/shared/mir/input/null_input_receiver_report.h 2013-11-07 00:22:14 +0000
92@@ -0,0 +1,46 @@
93+/*
94+ * Copyright © 2013 Canonical Ltd.
95+ *
96+ * This program is free software: you can redistribute it and/or modify
97+ * it under the terms of the GNU Lesser General Public License version 3 as
98+ * published by the Free Software Foundation.
99+ *
100+ * This program is distributed in the hope that it will be useful,
101+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
102+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
103+ * GNU Lesser General Public License for more details.
104+ *
105+ * You should have received a copy of the GNU Lesser General Public License
106+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
107+ *
108+ * Authored by: Robert Carr <robert.carr@canonical.com>
109+ */
110+
111+#ifndef MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_
112+#define MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_
113+
114+#include "mir/input/input_receiver_report.h"
115+
116+#include <mir_toolkit/event.h>
117+
118+namespace mir
119+{
120+namespace input
121+{
122+namespace receiver
123+{
124+
125+class NullInputReceiverReport : public InputReceiverReport
126+{
127+public:
128+ NullInputReceiverReport() = default;
129+ virtual ~NullInputReceiverReport() = default;
130+
131+ void received_event(MirEvent const& /* event */) {}
132+};
133+
134+}
135+}
136+}
137+
138+#endif /* MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_ */
139
140=== modified file 'include/test/mir_test_framework/input_testing_server_configuration.h'
141--- include/test/mir_test_framework/input_testing_server_configuration.h 2013-08-28 03:41:48 +0000
142+++ include/test/mir_test_framework/input_testing_server_configuration.h 2013-11-07 00:22:14 +0000
143@@ -65,9 +65,10 @@
144 std::shared_ptr<mir::input::InputConfiguration> the_input_configuration() override;
145 std::shared_ptr<mir::frontend::Shell> the_frontend_shell() override;
146
147+ mir::input::android::FakeEventHub* fake_event_hub;
148+
149 protected:
150 virtual void inject_input() = 0;
151- mir::input::android::FakeEventHub* fake_event_hub;
152
153 void wait_until_client_appears(std::string const& surface_name);
154
155
156=== modified file 'src/client/CMakeLists.txt'
157--- src/client/CMakeLists.txt 2013-10-21 16:02:28 +0000
158+++ src/client/CMakeLists.txt 2013-11-07 00:22:14 +0000
159@@ -29,6 +29,7 @@
160 mir_wait_handle.cpp
161 mir_surface.cpp
162 logging/rpc_report.cpp
163+ logging/input_receiver_report.cpp
164 default_connection_configuration.cpp
165 surface_map.cpp
166 lifecycle_control.cpp
167
168=== modified file 'src/client/default_connection_configuration.cpp'
169--- src/client/default_connection_configuration.cpp 2013-08-28 03:41:48 +0000
170+++ src/client/default_connection_configuration.cpp 2013-11-07 00:22:14 +0000
171@@ -24,7 +24,9 @@
172 #include "mir/logging/dumb_console_logger.h"
173 #include "native_client_platform_factory.h"
174 #include "mir/input/input_platform.h"
175+#include "mir/input/null_input_receiver_report.h"
176 #include "logging/rpc_report.h"
177+#include "logging/input_receiver_report.h"
178 #include "lttng/rpc_report.h"
179 #include "connection_surface_map.h"
180 #include "lifecycle_control.h"
181@@ -88,9 +90,9 @@
182 mcl::DefaultConnectionConfiguration::the_input_platform()
183 {
184 return input_platform(
185- []
186+ [this]
187 {
188- return mir::input::receiver::InputPlatform::create();
189+ return mir::input::receiver::InputPlatform::create(the_input_receiver_report());
190 });
191 }
192
193@@ -118,6 +120,22 @@
194 });
195 }
196
197+std::shared_ptr<mir::input::receiver::InputReceiverReport>
198+mcl::DefaultConnectionConfiguration::the_input_receiver_report()
199+{
200+ return input_receiver_report(
201+ [this] () -> std::shared_ptr<mir::input::receiver::InputReceiverReport>
202+ {
203+ auto val_raw = getenv("MIR_CLIENT_INPUT_RECEIVER_REPORT");
204+ std::string const val{val_raw ? val_raw : off_opt_val};
205+
206+ if (val == log_opt_val)
207+ return std::make_shared<mcl::logging::InputReceiverReport>(the_logger());
208+ else
209+ return std::make_shared<mir::input::receiver::NullInputReceiverReport>();
210+ });
211+}
212+
213 std::shared_ptr<mcl::DisplayConfiguration> mcl::DefaultConnectionConfiguration::the_display_configuration()
214 {
215 return display_configuration(
216
217=== modified file 'src/client/default_connection_configuration.h'
218--- src/client/default_connection_configuration.h 2013-08-28 03:41:48 +0000
219+++ src/client/default_connection_configuration.h 2013-11-07 00:22:14 +0000
220@@ -27,6 +27,13 @@
221
222 namespace mir
223 {
224+namespace input
225+{
226+namespace receiver
227+{
228+class InputReceiverReport;
229+}
230+}
231 namespace client
232 {
233
234@@ -50,6 +57,7 @@
235
236 virtual std::string the_socket_file();
237 virtual std::shared_ptr<rpc::RpcReport> the_rpc_report();
238+ virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report();
239
240 protected:
241 CachedPtr<rpc::MirBasicRpcChannel> rpc_channel;
242@@ -61,6 +69,7 @@
243 CachedPtr<LifecycleControl> lifecycle_control;
244
245 CachedPtr<rpc::RpcReport> rpc_report;
246+ CachedPtr<input::receiver::InputReceiverReport> input_receiver_report;
247
248 private:
249 std::string const socket_file;
250
251=== added file 'src/client/logging/input_receiver_report.cpp'
252--- src/client/logging/input_receiver_report.cpp 1970-01-01 00:00:00 +0000
253+++ src/client/logging/input_receiver_report.cpp 2013-11-07 00:22:14 +0000
254@@ -0,0 +1,125 @@
255+/*
256+ * Copyright © 2013 Canonical Ltd.
257+ *
258+ * This program is free software: you can redistribute it and/or modify
259+ * it under the terms of the GNU Lesser General Public License version 3 as
260+ * published by the Free Software Foundation.
261+ *
262+ * This program is distributed in the hope that it will be useful,
263+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
264+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
265+ * GNU Lesser General Public License for more details.
266+ *
267+ * You should have received a copy of the GNU Lesser General Public License
268+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
269+ *
270+ * Authored by: Robert Carr <robert.carr@canonical.com>
271+ */
272+
273+#include "input_receiver_report.h"
274+
275+#include "mir/logging/logger.h"
276+
277+#include <boost/throw_exception.hpp>
278+
279+#include <sstream>
280+#include <stdexcept>
281+
282+namespace ml = mir::logging;
283+namespace mcll = mir::client::logging;
284+
285+namespace
286+{
287+std::string const component{"input-receiver"};
288+}
289+
290+mcll::InputReceiverReport::InputReceiverReport(std::shared_ptr<ml::Logger> const& logger)
291+ : logger{logger}
292+{
293+}
294+
295+namespace
296+{
297+
298+static void format_key_event(std::stringstream &ss, MirKeyEvent const& ev)
299+{
300+ ss << "MirKeyEvent {" << std::endl;
301+ ss << " device_id: " << ev.device_id << std::endl;
302+ ss << " source_id: " << ev.source_id << std::endl;
303+ ss << " action: " << ev.action << std::endl;
304+ ss << " flags: " << ev.flags << std::endl;
305+ ss << " modifiers: " << ev.modifiers << std::endl;
306+ ss << " key_code: " << ev.key_code << std::endl;
307+ ss << " scan_code: " << ev.scan_code << std::endl;
308+ ss << " repeat_count: " << ev.repeat_count << std::endl;
309+ ss << " down_time: " << ev.down_time << std::endl;
310+ ss << " event_time: " << ev.event_time << std::endl;
311+ ss << " is_system_key: " << ev.is_system_key << std::endl;
312+ ss << "}";
313+}
314+static void format_motion_event(std::stringstream &ss, MirMotionEvent const& ev)
315+{
316+ ss << "MirMotionEvent{" << std::endl;
317+ ss << " type: motion" << std::endl;
318+ ss << " device_id: " << ev.device_id << std::endl;
319+ ss << " source_id: " << ev.source_id << std::endl;
320+ ss << " action: " << ev.action << std::endl;
321+ ss << " flags: " << ev.flags << std::endl;
322+ ss << " modifiers: " << ev.modifiers << std::endl;
323+ ss << " edge_flags: " << ev.edge_flags << std::endl;
324+ ss << " button_state: " << ev.button_state << std::endl;
325+ ss << " x_offset: " << ev.x_offset << std::endl;
326+ ss << " y_offset: " << ev.y_offset << std::endl;
327+ ss << " x_precision: " << ev.x_precision << std::endl;
328+ ss << " y_precision: " << ev.y_precision << std::endl;
329+ ss << " down_time: " << ev.down_time << std::endl;
330+ ss << " event_time: " << ev.event_time << std::endl;
331+ ss << " pointer_count: " << ev.pointer_count << std::endl;
332+ for (unsigned int i = 0; i < ev.pointer_count; i++)
333+ {
334+ ss << " pointer[" << i << "]{" << std::endl;
335+ ss << " id: " << ev.pointer_coordinates[i].id << std::endl;
336+ ss << " x: " << ev.pointer_coordinates[i].x << std::endl;
337+ ss << " raw_x: " << ev.pointer_coordinates[i].raw_x << std::endl;
338+ ss << " y: " << ev.pointer_coordinates[i].y << std::endl;
339+ ss << " raw_y: " << ev.pointer_coordinates[i].raw_y << std::endl;
340+ ss << " touch_major: " << ev.pointer_coordinates[i].touch_major << std::endl;
341+ ss << " touch_minor: " << ev.pointer_coordinates[i].touch_minor << std::endl;
342+ ss << " size: " << ev.pointer_coordinates[i].size << std::endl;
343+ ss << " pressure: " << ev.pointer_coordinates[i].pressure << std::endl;
344+ ss << " orientation: " << ev.pointer_coordinates[i].orientation << std::endl;
345+ ss << " vscroll: " << ev.pointer_coordinates[i].vscroll << std::endl;
346+ ss << " hscroll: " << ev.pointer_coordinates[i].hscroll << std::endl;
347+ ss << " }" << std::endl;
348+ }
349+ ss << "}";
350+}
351+
352+static void format_event(std::stringstream &ss, MirEvent const& ev)
353+{
354+ switch (ev.type)
355+ {
356+ case mir_event_type_key:
357+ format_key_event(ss, ev.key);
358+ break;
359+ case mir_event_type_motion:
360+ format_motion_event(ss, ev.motion);
361+ break;
362+ default:
363+ BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected event type"));
364+ }
365+}
366+
367+}
368+
369+void mcll::InputReceiverReport::received_event(
370+ MirEvent const& event)
371+{
372+ std::stringstream ss;
373+
374+ ss << "Received event:" << std::endl;
375+
376+ format_event(ss, event);
377+
378+ logger->log<ml::Logger::debug>(ss.str(), component);
379+}
380
381=== added file 'src/client/logging/input_receiver_report.h'
382--- src/client/logging/input_receiver_report.h 1970-01-01 00:00:00 +0000
383+++ src/client/logging/input_receiver_report.h 2013-11-07 00:22:14 +0000
384@@ -0,0 +1,54 @@
385+/*
386+ * Copyright © 2013 Canonical Ltd.
387+ *
388+ * This program is free software: you can redistribute it and/or modify
389+ * it under the terms of the GNU Lesser General Public License version 3 as
390+ * published by the Free Software Foundation.
391+ *
392+ * This program is distributed in the hope that it will be useful,
393+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
394+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
395+ * GNU Lesser General Public License for more details.
396+ *
397+ * You should have received a copy of the GNU Lesser General Public License
398+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
399+ *
400+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
401+ */
402+
403+#ifndef MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_
404+#define MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_
405+
406+#include "mir/input/input_receiver_report.h"
407+
408+#include <memory>
409+
410+namespace mir
411+{
412+
413+namespace logging
414+{
415+class Logger;
416+}
417+
418+namespace client
419+{
420+namespace logging
421+{
422+
423+class InputReceiverReport : public input::receiver::InputReceiverReport
424+{
425+public:
426+ InputReceiverReport(std::shared_ptr<mir::logging::Logger> const& logger);
427+
428+ void received_event(MirEvent const& event) override;
429+
430+private:
431+ std::shared_ptr<mir::logging::Logger> const logger;
432+};
433+
434+}
435+}
436+}
437+
438+#endif /* MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_ */
439
440=== modified file 'src/shared/input/android/android_input_platform.cpp'
441--- src/shared/input/android/android_input_platform.cpp 2013-05-13 23:20:52 +0000
442+++ src/shared/input/android/android_input_platform.cpp 2013-11-07 00:22:14 +0000
443@@ -20,10 +20,13 @@
444 #include "android_input_receiver.h"
445 #include "android_input_receiver_thread.h"
446
447+#include "mir/input/null_input_receiver_report.h"
448+
449 namespace mircv = mir::input::receiver;
450 namespace mircva = mircv::android;
451
452-mircva::AndroidInputPlatform::AndroidInputPlatform()
453+mircva::AndroidInputPlatform::AndroidInputPlatform(std::shared_ptr<mircv::InputReceiverReport> const& report)
454+ : report(report)
455 {
456 }
457
458@@ -34,11 +37,16 @@
459 std::shared_ptr<mircv::InputReceiverThread> mircva::AndroidInputPlatform::create_input_thread(
460 int fd, std::function<void(MirEvent*)> const& callback)
461 {
462- auto receiver = std::make_shared<mircva::InputReceiver>(fd);
463+ auto receiver = std::make_shared<mircva::InputReceiver>(fd, report);
464 return std::make_shared<mircva::InputReceiverThread>(receiver, callback);
465 }
466
467 std::shared_ptr<mircv::InputPlatform> mircv::InputPlatform::create()
468 {
469- return std::make_shared<mircva::AndroidInputPlatform>();
470+ return create(std::make_shared<mircv::NullInputReceiverReport>());
471+}
472+
473+std::shared_ptr<mircv::InputPlatform> mircv::InputPlatform::create(std::shared_ptr<mircv::InputReceiverReport> const& report)
474+{
475+ return std::make_shared<mircva::AndroidInputPlatform>(report);
476 }
477
478=== modified file 'src/shared/input/android/android_input_platform.h'
479--- src/shared/input/android/android_input_platform.h 2013-05-13 23:20:52 +0000
480+++ src/shared/input/android/android_input_platform.h 2013-11-07 00:22:14 +0000
481@@ -34,7 +34,7 @@
482 class AndroidInputPlatform : public InputPlatform
483 {
484 public:
485- AndroidInputPlatform();
486+ AndroidInputPlatform(std::shared_ptr<InputReceiverReport> const& report);
487 virtual ~AndroidInputPlatform();
488
489 std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback);
490@@ -42,6 +42,9 @@
491 protected:
492 AndroidInputPlatform(const AndroidInputPlatform&) = delete;
493 AndroidInputPlatform& operator=(const AndroidInputPlatform&) = delete;
494+
495+private:
496+ std::shared_ptr<InputReceiverReport> const report;
497 };
498
499 }
500
501=== modified file 'src/shared/input/android/android_input_receiver.cpp'
502--- src/shared/input/android/android_input_receiver.cpp 2013-05-24 18:20:37 +0000
503+++ src/shared/input/android/android_input_receiver.cpp 2013-11-07 00:22:14 +0000
504@@ -19,6 +19,7 @@
505 #include "android_input_receiver.h"
506
507 #include "mir/input/xkb_mapper.h"
508+#include "mir/input/input_receiver_report.h"
509 #include "mir/input/android/android_input_lexicon.h"
510
511 #include <androidfw/InputTransport.h>
512@@ -29,8 +30,10 @@
513
514 namespace mia = mir::input::android;
515
516-mircva::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel)
517+mircva::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel,
518+ std::shared_ptr<mircv::InputReceiverReport> const& report)
519 : input_channel(input_channel),
520+ report(report),
521 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
522 looper(new droidinput::Looper(true)),
523 fd_added(false),
524@@ -38,8 +41,10 @@
525 {
526 }
527
528-mircva::InputReceiver::InputReceiver(int fd)
529+mircva::InputReceiver::InputReceiver(int fd,
530+ std::shared_ptr<mircv::InputReceiverReport> const& report)
531 : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)),
532+ report(report),
533 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
534 looper(new droidinput::Looper(true)),
535 fd_added(false),
536@@ -84,6 +89,8 @@
537 map_key_event(xkb_mapper, ev);
538
539 input_consumer->sendFinishedSignal(event_sequence_id, true);
540+
541+ report->received_event(ev);
542
543 return true;
544 }
545
546=== modified file 'src/shared/input/android/android_input_receiver.h'
547--- src/shared/input/android/android_input_receiver.h 2013-05-24 18:20:37 +0000
548+++ src/shared/input/android/android_input_receiver.h 2013-11-07 00:22:14 +0000
549@@ -43,6 +43,7 @@
550 namespace receiver
551 {
552 class XKBMapper;
553+class InputReceiverReport;
554
555 namespace android
556 {
557@@ -51,8 +52,10 @@
558 class InputReceiver
559 {
560 public:
561- InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel);
562- InputReceiver(int fd);
563+ InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel,
564+ std::shared_ptr<InputReceiverReport> const& report);
565+ InputReceiver(int fd,
566+ std::shared_ptr<InputReceiverReport> const& report);
567
568 virtual ~InputReceiver();
569 int fd() const;
570@@ -71,6 +74,8 @@
571
572 private:
573 droidinput::sp<droidinput::InputChannel> input_channel;
574+ std::shared_ptr<InputReceiverReport> const report;
575+
576 std::shared_ptr<droidinput::InputConsumer> input_consumer;
577 droidinput::PreallocatedInputEventFactory event_factory;
578 droidinput::sp<droidinput::Looper> looper;
579
580=== modified file 'tests/acceptance-tests/test_client_input.cpp'
581--- tests/acceptance-tests/test_client_input.cpp 2013-10-28 21:41:27 +0000
582+++ tests/acceptance-tests/test_client_input.cpp 2013-11-07 00:22:14 +0000
583@@ -248,6 +248,16 @@
584 return true;
585 }
586
587+MATCHER(HoverMoveEvent, "")
588+{
589+ if (arg->type != mir_event_type_motion)
590+ return false;
591+ if (arg->motion.action != mir_motion_action_hover_move)
592+ return false;
593+
594+ return true;
595+}
596+
597 MATCHER_P2(ButtonDownEvent, x, y, "")
598 {
599 if (arg->type != mir_event_type_motion)
600@@ -302,194 +312,6 @@
601
602 }
603
604-
605-using TestClientInput = BespokeDisplayServerTestFixture;
606-
607-TEST_F(TestClientInput, clients_receive_key_input)
608-{
609- using namespace ::testing;
610-
611- int const num_events_produced = 3;
612- static std::string const test_client_name = "1";
613-
614- mtf::CrossProcessSync fence;
615-
616- struct ServerConfiguration : mtf::InputTestingServerConfiguration
617- {
618- mtf::CrossProcessSync input_cb_setup_fence;
619-
620- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
621- : input_cb_setup_fence(input_cb_setup_fence)
622- {
623- }
624-
625- void inject_input()
626- {
627- wait_until_client_appears(test_client_name);
628- input_cb_setup_fence.wait_for_signal_ready_for();
629-
630- for (int i = 0; i < num_events_produced; i++)
631- fake_event_hub->synthesize_event(mis::a_key_down_event()
632- .of_scancode(KEY_ENTER));
633- }
634- } server_config(fence);
635- launch_server_process(server_config);
636-
637- struct KeyReceivingClient : InputClient
638- {
639- KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
640- void expect_input(mt::WaitCondition& events_received) override
641- {
642- using namespace ::testing;
643- InSequence seq;
644-
645- EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(2);
646- EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(1)
647- .WillOnce(mt::WakeUp(&events_received));
648- }
649- } client_config(fence);
650- launch_client_process(client_config);
651-}
652-
653-TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
654-{
655- using namespace ::testing;
656- static std::string const test_client_name = "1";
657- mtf::CrossProcessSync fence;
658-
659- struct ServerConfiguration : mtf::InputTestingServerConfiguration
660- {
661- mtf::CrossProcessSync input_cb_setup_fence;
662-
663- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
664- : input_cb_setup_fence(input_cb_setup_fence)
665- {
666- }
667-
668- void inject_input()
669- {
670- wait_until_client_appears(test_client_name);
671- input_cb_setup_fence.wait_for_signal_ready_for();
672-
673- fake_event_hub->synthesize_event(mis::a_key_down_event()
674- .of_scancode(KEY_LEFTSHIFT));
675- fake_event_hub->synthesize_event(mis::a_key_down_event()
676- .of_scancode(KEY_4));
677-
678- }
679- } server_config{fence};
680- launch_server_process(server_config);
681-
682- struct KeyReceivingClient : InputClient
683- {
684- KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
685-
686- void expect_input(mt::WaitCondition& events_received) override
687- {
688- using namespace ::testing;
689-
690- InSequence seq;
691- EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1);
692- EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1)
693- .WillOnce(mt::WakeUp(&events_received));
694- }
695- } client_config{fence};
696- launch_client_process(client_config);
697-}
698-
699-TEST_F(TestClientInput, clients_receive_motion_inside_window)
700-{
701- using namespace ::testing;
702- static std::string const test_client_name = "1";
703- mtf::CrossProcessSync fence;
704-
705- struct ServerConfiguration : public mtf::InputTestingServerConfiguration
706- {
707- mtf::CrossProcessSync input_cb_setup_fence;
708-
709- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
710- : input_cb_setup_fence(input_cb_setup_fence)
711- {
712- }
713-
714- void inject_input()
715- {
716- wait_until_client_appears(test_client_name);
717- input_cb_setup_fence.wait_for_signal_ready_for();
718-
719- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1,
720- InputClient::surface_height - 1));
721- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2));
722- }
723- } server_config{fence};
724- launch_server_process(server_config);
725-
726- struct MotionReceivingClient : InputClient
727- {
728- MotionReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
729-
730- void expect_input(mt::WaitCondition& events_received) override
731- {
732- using namespace ::testing;
733-
734- InSequence seq;
735-
736- // We should see the cursor enter
737- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);
738- EXPECT_CALL(*handler, handle_input(
739- MotionEventWithPosition(InputClient::surface_width - 1,
740- InputClient::surface_height - 1))).Times(1)
741- .WillOnce(mt::WakeUp(&events_received));
742- // But we should not receive an event for the second movement outside of our surface!
743- }
744- } client_config{fence};
745- launch_client_process(client_config);
746-}
747-
748-TEST_F(TestClientInput, clients_receive_button_events_inside_window)
749-{
750- using namespace ::testing;
751-
752- static std::string const test_client_name = "1";
753- mtf::CrossProcessSync fence;
754-
755- struct ServerConfiguration : public mtf::InputTestingServerConfiguration
756- {
757- mtf::CrossProcessSync input_cb_setup_fence;
758-
759- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
760- : input_cb_setup_fence(input_cb_setup_fence)
761- {
762- }
763-
764- void inject_input()
765- {
766- wait_until_client_appears(test_client_name);
767- input_cb_setup_fence.wait_for_signal_ready_for();
768-
769- fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
770- }
771- } server_config{fence};
772- launch_server_process(server_config);
773-
774- struct ButtonReceivingClient : InputClient
775- {
776- ButtonReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
777-
778- void expect_input(mt::WaitCondition& events_received) override
779- {
780- using namespace ::testing;
781-
782- InSequence seq;
783-
784- // The cursor starts at (0, 0).
785- EXPECT_CALL(*handler, handle_input(ButtonDownEvent(0, 0))).Times(1)
786- .WillOnce(mt::WakeUp(&events_received));
787- }
788- } client_config{fence};
789- launch_client_process(client_config);
790-}
791-
792 namespace
793 {
794 typedef std::map<std::string, geom::Rectangle> GeometryMap;
795@@ -497,34 +319,251 @@
796
797 struct StaticPlacementStrategy : public msh::PlacementStrategy
798 {
799- StaticPlacementStrategy(GeometryMap const& positions,
800+ StaticPlacementStrategy(std::shared_ptr<msh::PlacementStrategy> const& underlying_strategy,
801+ GeometryMap const& positions,
802 DepthMap const& depths)
803- : surface_geometry_by_name(positions),
804+ : underlying_strategy(underlying_strategy),
805+ surface_geometry_by_name(positions),
806 surface_depths_by_name(depths)
807 {
808 }
809
810- StaticPlacementStrategy(GeometryMap const& positions)
811- : StaticPlacementStrategy(positions, DepthMap())
812+ StaticPlacementStrategy(std::shared_ptr<msh::PlacementStrategy> const& underlying_strategy,
813+ GeometryMap const& positions)
814+ : StaticPlacementStrategy(underlying_strategy, positions, DepthMap())
815 {
816 }
817
818- msh::SurfaceCreationParameters place(msh::Session const&, msh::SurfaceCreationParameters const& request_parameters)
819+ msh::SurfaceCreationParameters place(msh::Session const& session, msh::SurfaceCreationParameters const& request_parameters)
820 {
821 auto placed = request_parameters;
822 auto const& name = request_parameters.name;
823- auto geometry = surface_geometry_by_name[name];
824-
825- placed.top_left = geometry.top_left;
826- placed.size = geometry.size;
827+
828+ auto it = surface_geometry_by_name.find(name);
829+ if (it != surface_geometry_by_name.end())
830+ {
831+ auto const& geometry = it->second;
832+ placed.top_left = geometry.top_left;
833+ placed.size = geometry.size;
834+ }
835+ else
836+ {
837+ placed = underlying_strategy->place(session, placed);
838+ }
839 placed.depth = surface_depths_by_name[name];
840
841 return placed;
842 }
843+
844+ std::shared_ptr<msh::PlacementStrategy> const underlying_strategy;
845 GeometryMap surface_geometry_by_name;
846 DepthMap surface_depths_by_name;
847 };
848
849+std::shared_ptr<mtf::InputTestingServerConfiguration>
850+make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence,
851+ int number_of_clients,
852+ std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events,
853+ GeometryMap const& client_geometry_map, DepthMap const& client_depth_map)
854+{
855+ struct ServerConfiguration : mtf::InputTestingServerConfiguration
856+ {
857+ mtf::CrossProcessSync input_cb_setup_fence;
858+ int const number_of_clients;
859+ std::function<void(mtf::InputTestingServerConfiguration& server)> const produce_events;
860+ GeometryMap const client_geometry;
861+ DepthMap const client_depth;
862+
863+ ServerConfiguration(mtf::CrossProcessSync const& input_cb_setup_fence, int number_of_clients,
864+ std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events,
865+ GeometryMap const& client_geometry, DepthMap const& client_depth)
866+ : input_cb_setup_fence(input_cb_setup_fence),
867+ number_of_clients(number_of_clients),
868+ produce_events(produce_events),
869+ client_geometry(client_geometry),
870+ client_depth(client_depth)
871+ {
872+ }
873+
874+ std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
875+ {
876+ return std::make_shared<StaticPlacementStrategy>(InputTestingServerConfiguration::the_shell_placement_strategy(),
877+ client_geometry, client_depth);
878+ }
879+
880+ void inject_input()
881+ {
882+ for (int i = 1; i < number_of_clients + 1; i++)
883+ EXPECT_EQ(i, input_cb_setup_fence.wait_for_signal_ready_for());
884+ produce_events(*this);
885+ }
886+ };
887+ return std::make_shared<ServerConfiguration>(client_ready_fence, number_of_clients,
888+ produce_events, client_geometry_map, client_depth_map);
889+}
890+
891+std::shared_ptr<mtf::InputTestingServerConfiguration>
892+make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence, int number_of_clients,
893+ std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events)
894+{
895+ return make_event_producing_server(client_ready_fence, number_of_clients,
896+ produce_events, GeometryMap(), DepthMap());
897+}
898+
899+std::shared_ptr<InputClient>
900+make_event_expecting_client(std::string const& client_name, mtf::CrossProcessSync const& client_ready_fence,
901+ std::function<void(MockInputHandler &, mt::WaitCondition&)> const& expect_input)
902+{
903+ struct EventReceivingClient : InputClient
904+ {
905+ std::function<void(MockInputHandler&, mt::WaitCondition&)> const expect_cb;
906+
907+ EventReceivingClient(mtf::CrossProcessSync const& client_ready_fence, std::string const& client_name,
908+ std::function<void(MockInputHandler&, mt::WaitCondition&)> const& expect_cb)
909+ : InputClient(client_ready_fence, client_name),
910+ expect_cb(expect_cb)
911+ {
912+ }
913+ void expect_input(mt::WaitCondition& events_received) override
914+ {
915+ expect_cb(*handler, events_received);
916+ }
917+ };
918+ return std::make_shared<EventReceivingClient>(client_ready_fence, client_name, expect_input);
919+}
920+
921+std::shared_ptr<InputClient>
922+make_event_expecting_client(mtf::CrossProcessSync const& client_ready_fence,
923+ std::function<void(MockInputHandler &, mt::WaitCondition&)> const& expect_input)
924+{
925+ return make_event_expecting_client("input-test-client", client_ready_fence, expect_input);
926+}
927+
928+}
929+
930+
931+using TestClientInput = BespokeDisplayServerTestFixture;
932+
933+TEST_F(TestClientInput, clients_receive_key_input)
934+{
935+ using namespace ::testing;
936+
937+ static std::string const test_client_name = "1";
938+
939+ mtf::CrossProcessSync fence;
940+
941+ auto server_config = make_event_producing_server(fence, 1,
942+ [&](mtf::InputTestingServerConfiguration& server)
943+ {
944+ int const num_events_produced = 3;
945+
946+ for (int i = 0; i < num_events_produced; i++)
947+ server.fake_event_hub->synthesize_event(mis::a_key_down_event()
948+ .of_scancode(KEY_ENTER));
949+ });
950+ launch_server_process(*server_config);
951+
952+ auto client_config = make_event_expecting_client(fence,
953+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
954+ {
955+ using namespace ::testing;
956+ InSequence seq;
957+
958+ EXPECT_CALL(handler, handle_input(KeyDownEvent())).Times(2);
959+ EXPECT_CALL(handler, handle_input(KeyDownEvent())).Times(1)
960+ .WillOnce(mt::WakeUp(&events_received));
961+
962+ });
963+ launch_client_process(*client_config);
964+}
965+
966+TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
967+{
968+ using namespace ::testing;
969+ static std::string const test_client_name = "1";
970+ mtf::CrossProcessSync fence;
971+
972+ auto server_config = make_event_producing_server(fence, 1,
973+ [&](mtf::InputTestingServerConfiguration& server)
974+ {
975+ server.fake_event_hub->synthesize_event(mis::a_key_down_event()
976+ .of_scancode(KEY_LEFTSHIFT));
977+ server.fake_event_hub->synthesize_event(mis::a_key_down_event()
978+ .of_scancode(KEY_4));
979+ });
980+ launch_server_process(*server_config);
981+
982+ auto client_config = make_event_expecting_client(fence,
983+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
984+ {
985+ using namespace ::testing;
986+ InSequence seq;
987+
988+ EXPECT_CALL(handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1);
989+ EXPECT_CALL(handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1)
990+ .WillOnce(mt::WakeUp(&events_received));
991+ });
992+ launch_client_process(*client_config);
993+}
994+
995+TEST_F(TestClientInput, clients_receive_motion_inside_window)
996+{
997+ using namespace ::testing;
998+ static std::string const test_client_name = "1";
999+ mtf::CrossProcessSync fence;
1000+
1001+ auto server_config = make_event_producing_server(fence, 1,
1002+ [&](mtf::InputTestingServerConfiguration& server)
1003+ {
1004+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1,
1005+ InputClient::surface_height - 1));
1006+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2));
1007+ });
1008+ launch_server_process(*server_config);
1009+
1010+ auto client_config = make_event_expecting_client(fence,
1011+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1012+ {
1013+ using namespace ::testing;
1014+ InSequence seq;
1015+
1016+ // We should see the cursor enter
1017+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(1);
1018+ EXPECT_CALL(handler, handle_input(
1019+ MotionEventWithPosition(InputClient::surface_width - 1,
1020+ InputClient::surface_height - 1))).Times(1)
1021+ .WillOnce(mt::WakeUp(&events_received));
1022+ // But we should not receive an event for the second movement outside of our surface!
1023+ });
1024+ launch_client_process(*client_config);
1025+}
1026+
1027+TEST_F(TestClientInput, clients_receive_button_events_inside_window)
1028+{
1029+ using namespace ::testing;
1030+
1031+ static std::string const test_client_name = "1";
1032+ mtf::CrossProcessSync fence;
1033+
1034+ auto server_config = make_event_producing_server(fence, 1,
1035+ [&](mtf::InputTestingServerConfiguration& server)
1036+ {
1037+ server.fake_event_hub->synthesize_event(mis::a_button_down_event()
1038+ .of_button(BTN_LEFT).with_action(mis::EventAction::Down));
1039+ });
1040+ launch_server_process(*server_config);
1041+
1042+ auto client_config = make_event_expecting_client(fence,
1043+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1044+ {
1045+ using namespace ::testing;
1046+ InSequence seq;
1047+
1048+ // The cursor starts at (0, 0).
1049+ EXPECT_CALL(handler, handle_input(ButtonDownEvent(0, 0))).Times(1)
1050+ .WillOnce(mt::WakeUp(&events_received));
1051+ });
1052+ launch_client_process(*client_config);
1053 }
1054
1055 TEST_F(TestClientInput, multiple_clients_receive_motion_inside_windows)
1056@@ -539,77 +578,42 @@
1057 static std::string const test_client_2 = "2";
1058 mtf::CrossProcessSync fence;
1059
1060- struct ServerConfiguration : mtf::InputTestingServerConfiguration
1061- {
1062- mtf::CrossProcessSync input_cb_setup_fence;
1063-
1064- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
1065- : input_cb_setup_fence(input_cb_setup_fence)
1066- {
1067- }
1068-
1069- std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
1070- {
1071- static GeometryMap positions;
1072- positions[test_client_1] = geom::Rectangle{geom::Point{0, 0},
1073- geom::Size{client_width, client_height}};
1074- positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2},
1075- geom::Size{client_width, client_height}};
1076-
1077- return std::make_shared<StaticPlacementStrategy>(positions);
1078- }
1079-
1080- void inject_input() override
1081- {
1082- wait_until_client_appears(test_client_1);
1083- EXPECT_EQ(1, input_cb_setup_fence.wait_for_signal_ready_for());
1084- wait_until_client_appears(test_client_2);
1085- EXPECT_EQ(2, input_cb_setup_fence.wait_for_signal_ready_for());
1086-
1087+ static GeometryMap positions;
1088+ positions[test_client_1] = geom::Rectangle{geom::Point{0, 0},
1089+ geom::Size{client_width, client_height}};
1090+ positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2},
1091+ geom::Size{client_width, client_height}};
1092+
1093+ auto server_config = make_event_producing_server(fence, 2,
1094+ [&](mtf::InputTestingServerConfiguration& server)
1095+ {
1096 // In the bounds of the first surface
1097- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1));
1098+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1));
1099 // In the bounds of the second surface
1100- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2));
1101- }
1102- } server_config{fence};
1103-
1104- launch_server_process(server_config);
1105-
1106- struct InputClientOne : InputClient
1107- {
1108- InputClientOne(const mtf::CrossProcessSync& fence)
1109- : InputClient(fence, test_client_1)
1110- {
1111- }
1112-
1113- void expect_input(mt::WaitCondition& events_received) override
1114- {
1115- InSequence seq;
1116- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);
1117- EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1);
1118- EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(1)
1119- .WillOnce(mt::WakeUp(&events_received));
1120- }
1121- } client_1{fence};
1122-
1123- struct InputClientTwo : InputClient
1124- {
1125- InputClientTwo(const mtf::CrossProcessSync& fence)
1126- : InputClient(fence, test_client_2)
1127- {
1128- }
1129-
1130- void expect_input(mt::WaitCondition& events_received) override
1131- {
1132- InSequence seq;
1133- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);
1134- EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1)
1135- .WillOnce(mt::WakeUp(&events_received));
1136- }
1137- } client_2{fence};
1138-
1139- launch_client_process(client_1);
1140- launch_client_process(client_2);
1141+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2));
1142+ }, positions, DepthMap());
1143+ launch_server_process(*server_config);
1144+
1145+ auto client_1 = make_event_expecting_client(test_client_1, fence,
1146+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1147+ {
1148+ InSequence seq;
1149+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(1);
1150+ EXPECT_CALL(handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1);
1151+ EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(1)
1152+ .WillOnce(mt::WakeUp(&events_received));
1153+ });
1154+ auto client_2 = make_event_expecting_client(test_client_2, fence,
1155+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1156+ {
1157+ InSequence seq;
1158+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(1);
1159+ EXPECT_CALL(handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1)
1160+ .WillOnce(mt::WakeUp(&events_received));
1161+ });
1162+
1163+ launch_client_process(*client_1);
1164+ launch_client_process(*client_2);
1165 }
1166
1167 namespace
1168@@ -639,6 +643,7 @@
1169 std::vector<geom::Rectangle> const input_rectangles;
1170 };
1171 }
1172+
1173 TEST_F(TestClientInput, clients_do_not_receive_motion_outside_input_region)
1174 {
1175 using namespace ::testing;
1176@@ -670,7 +675,7 @@
1177 static GeometryMap positions;
1178 positions[test_client_name] = screen_geometry;
1179
1180- return std::make_shared<StaticPlacementStrategy>(positions);
1181+ return std::make_shared<StaticPlacementStrategy>(InputTestingServerConfiguration::the_shell_placement_strategy(), positions);
1182 }
1183 std::shared_ptr<msh::SurfaceFactory> the_shell_surface_factory() override
1184 {
1185@@ -697,35 +702,26 @@
1186 fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
1187 }
1188 } server_config{fence};
1189-
1190 launch_server_process(server_config);
1191
1192- struct ClientConfig : InputClient
1193- {
1194- ClientConfig(const mtf::CrossProcessSync& fence)
1195- : InputClient(fence, test_client_name)
1196- {
1197- }
1198-
1199- void expect_input(mt::WaitCondition& events_received) override
1200- {
1201-
1202- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1203- EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1204- EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber());
1205+ auto client_config = make_event_expecting_client(test_client_name, fence,
1206+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1207+ {
1208+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1209+ EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1210+ EXPECT_CALL(handler, handle_input(MovementEvent())).Times(AnyNumber());
1211
1212 {
1213 // We should see two of the three button pairs.
1214 InSequence seq;
1215- EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1);
1216- EXPECT_CALL(*handler, handle_input(ButtonUpEvent(1, 1))).Times(1);
1217- EXPECT_CALL(*handler, handle_input(ButtonDownEvent(99, 99))).Times(1);
1218- EXPECT_CALL(*handler, handle_input(ButtonUpEvent(99, 99))).Times(1)
1219+ EXPECT_CALL(handler, handle_input(ButtonDownEvent(1, 1))).Times(1);
1220+ EXPECT_CALL(handler, handle_input(ButtonUpEvent(1, 1))).Times(1);
1221+ EXPECT_CALL(handler, handle_input(ButtonDownEvent(99, 99))).Times(1);
1222+ EXPECT_CALL(handler, handle_input(ButtonUpEvent(99, 99))).Times(1)
1223 .WillOnce(mt::WakeUp(&events_received));
1224 }
1225- }
1226- } client_config{fence};
1227- launch_client_process(client_config);
1228+ });
1229+ launch_client_process(*client_config);
1230 }
1231
1232 TEST_F(TestClientInput, surfaces_obscure_motion_events_by_stacking)
1233@@ -742,98 +738,62 @@
1234 static geom::Rectangle const screen_geometry{geom::Point{0, 0},
1235 geom::Size{screen_width, screen_height}};
1236
1237- struct ServerConfiguration : mtf::InputTestingServerConfiguration
1238- {
1239- mtf::CrossProcessSync input_cb_setup_fence;
1240-
1241- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
1242- : input_cb_setup_fence(input_cb_setup_fence)
1243- {
1244- }
1245-
1246- std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
1247- {
1248- static GeometryMap positions;
1249- positions[test_client_name_1] = screen_geometry;
1250-
1251- auto smaller_geometry = screen_geometry;
1252- smaller_geometry.size.width = geom::Width{screen_width/2};
1253- positions[test_client_name_2] = smaller_geometry;
1254-
1255- static DepthMap depths;
1256- depths[test_client_name_1] = ms::DepthId{0};
1257- depths[test_client_name_2] = ms::DepthId{1};
1258-
1259- return std::make_shared<StaticPlacementStrategy>(positions, depths);
1260- }
1261-
1262- void inject_input() override
1263- {
1264- wait_until_client_appears(test_client_name_1);
1265- input_cb_setup_fence.wait_for_signal_ready_for();
1266- wait_until_client_appears(test_client_name_2);
1267- input_cb_setup_fence.wait_for_signal_ready_for();
1268-
1269+ static GeometryMap positions;
1270+ positions[test_client_name_1] = screen_geometry;
1271+
1272+ auto smaller_geometry = screen_geometry;
1273+ smaller_geometry.size.width = geom::Width{screen_width/2};
1274+ positions[test_client_name_2] = smaller_geometry;
1275+
1276+ static DepthMap depths;
1277+ depths[test_client_name_1] = ms::DepthId{0};
1278+ depths[test_client_name_2] = ms::DepthId{1};
1279+
1280+ auto server_config = make_event_producing_server(fence, 2,
1281+ [&](mtf::InputTestingServerConfiguration& server)
1282+ {
1283 // First we will move the cursor in to the region where client 2 obscures client 1
1284- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1));
1285- fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
1286- fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
1287+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1));
1288+ server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
1289+ server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
1290 // Now we move to the unobscured region of client 1
1291- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0));
1292- fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
1293- fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
1294- }
1295- } server_config{fence};
1296-
1297- launch_server_process(server_config);
1298-
1299- struct ClientConfigOne : InputClient
1300- {
1301- ClientConfigOne(const mtf::CrossProcessSync& fence)
1302- : InputClient(fence, test_client_name_1)
1303- {
1304- }
1305-
1306- void expect_input(mt::WaitCondition& events_received) override
1307- {
1308- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1309- EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1310- EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber());
1311-
1312+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0));
1313+ server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
1314+ server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
1315+ }, positions, depths);
1316+ launch_server_process(*server_config);
1317+
1318+ auto client_config_1 = make_event_expecting_client(test_client_name_1, fence,
1319+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1320+ {
1321+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1322+ EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1323+ EXPECT_CALL(handler, handle_input(MovementEvent())).Times(AnyNumber());
1324 {
1325 // We should only see one button event sequence.
1326 InSequence seq;
1327- EXPECT_CALL(*handler, handle_input(ButtonDownEvent(51, 1))).Times(1);
1328- EXPECT_CALL(*handler, handle_input(ButtonUpEvent(51, 1))).Times(1)
1329+ EXPECT_CALL(handler, handle_input(ButtonDownEvent(51, 1))).Times(1);
1330+ EXPECT_CALL(handler, handle_input(ButtonUpEvent(51, 1))).Times(1)
1331 .WillOnce(mt::WakeUp(&events_received));
1332 }
1333- }
1334- } client_config_1{fence};
1335- launch_client_process(client_config_1);
1336-
1337- struct ClientConfigTwo : InputClient
1338- {
1339- ClientConfigTwo(const mtf::CrossProcessSync& fence)
1340- : InputClient(fence, test_client_name_2)
1341- {
1342- }
1343-
1344- void expect_input(mt::WaitCondition& events_received) override
1345- {
1346- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1347- EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1348- EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber());
1349-
1350+ });
1351+ auto client_config_2 = make_event_expecting_client(test_client_name_2, fence,
1352+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1353+ {
1354+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1355+ EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1356+ EXPECT_CALL(handler, handle_input(MovementEvent())).Times(AnyNumber());
1357 {
1358 // Likewise we should only see one button sequence.
1359 InSequence seq;
1360- EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1);
1361- EXPECT_CALL(*handler, handle_input(ButtonUpEvent(1, 1))).Times(1)
1362+ EXPECT_CALL(handler, handle_input(ButtonDownEvent(1, 1))).Times(1);
1363+ EXPECT_CALL(handler, handle_input(ButtonUpEvent(1, 1))).Times(1)
1364 .WillOnce(mt::WakeUp(&events_received));
1365 }
1366- }
1367- } client_config_2{fence};
1368- launch_client_process(client_config_2);
1369+ });
1370+
1371+ launch_client_process(*client_config_1);
1372+ launch_client_process(*client_config_2);
1373 }
1374
1375 namespace
1376@@ -853,93 +813,48 @@
1377 static std::string const test_client_name = "1";
1378 static std::string const test_client_2_name = "2";
1379 mtf::CrossProcessSync fence, first_client_ready_fence, second_client_done_fence;
1380-
1381- struct ServerConfiguration : public mtf::InputTestingServerConfiguration
1382- {
1383- mtf::CrossProcessSync input_cb_setup_fence;
1384- mtf::CrossProcessSync second_client_done_fence;
1385-
1386- ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence,
1387- const mtf::CrossProcessSync& second_client_done_fence)
1388- : input_cb_setup_fence(input_cb_setup_fence),
1389- second_client_done_fence(second_client_done_fence)
1390- {
1391- }
1392-
1393- void hide_session_by_name(std::string const& session_name)
1394- {
1395- the_shell_session_container()->for_each([&](std::shared_ptr<msh::Session> const& session) -> void
1396- {
1397- if (session->name() == session_name)
1398- session->hide();
1399- });
1400- }
1401-
1402- void inject_input()
1403- {
1404- wait_until_client_appears(test_client_name);
1405- wait_until_client_appears(test_client_2_name);
1406- input_cb_setup_fence.wait_for_signal_ready_for();
1407-
1408+
1409+ static DepthMap depths;
1410+ depths[test_client_name] = ms::DepthId{0};
1411+ depths[test_client_2_name] = ms::DepthId{1};
1412+
1413+ auto server_config = make_event_producing_server(fence, 2,
1414+ [&](mtf::InputTestingServerConfiguration& server)
1415+ {
1416 // We send one event and then hide the surface on top before sending the next.
1417- // So we expect each of the two surfaces to receive one event pair.
1418- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));
1419-
1420+ // So we expect each of the two surfaces to receive one even
1421+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));
1422 // We use a fence to ensure we do not hide the client
1423 // before event dispatch occurs
1424 second_client_done_fence.wait_for_signal_ready_for();
1425- hide_session_by_name(test_client_2_name);
1426-
1427- fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));
1428- }
1429- } server_config{fence, second_client_done_fence};
1430- launch_server_process(server_config);
1431-
1432- struct ButtonClientOne : InputClient
1433- {
1434- ButtonClientOne(const mtf::CrossProcessSync& fence)
1435- : InputClient(fence, test_client_name)
1436- {
1437- }
1438-
1439- void expect_input(mt::WaitCondition& events_received) override
1440- {
1441- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1442- EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1443- EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(2, 2))).Times(1)
1444+
1445+ server.the_shell_session_container()->for_each([&](std::shared_ptr<msh::Session> const& session) -> void
1446+ {
1447+ if (session->name() == test_client_2_name)
1448+ session->hide();
1449+ });
1450+
1451+ server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));
1452+ }, GeometryMap(), depths);
1453+ launch_server_process(*server_config);
1454+
1455+ auto client_config_1 = make_event_expecting_client(test_client_name, fence,
1456+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1457+ {
1458+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1459+ EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1460+ EXPECT_CALL(handler, handle_input(MotionEventWithPosition(2, 2))).Times(1)
1461 .WillOnce(mt::WakeUp(&events_received));
1462- }
1463- } client_1{first_client_ready_fence};
1464- struct ButtonClientTwo : InputClient
1465- {
1466- mtf::CrossProcessSync first_client_ready;
1467- mtf::CrossProcessSync done_fence;
1468-
1469- ButtonClientTwo(mtf::CrossProcessSync const& fence, mtf::CrossProcessSync const& first_client_ready,
1470- mtf::CrossProcessSync const& done_fence)
1471- : InputClient(fence, test_client_2_name),
1472- first_client_ready(first_client_ready),
1473- done_fence(done_fence)
1474- {
1475- }
1476- void exec()
1477- {
1478- // Ensure we stack on top of the first client
1479- first_client_ready.wait_for_signal_ready_for();
1480- InputClient::exec();
1481- }
1482-
1483- void expect_input(mt::WaitCondition& events_received) override
1484- {
1485- EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1486- EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1487- EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(1, 1))).Times(1)
1488- .WillOnce(DoAll(SignalFence(&done_fence), mt::WakeUp(&events_received)));
1489- }
1490- } client_2{fence, first_client_ready_fence, second_client_done_fence};
1491-
1492- // Client 2 is launched second so will be the first to receive input
1493-
1494- launch_client_process(client_1);
1495- launch_client_process(client_2);
1496+ });
1497+ auto client_config_2 = make_event_expecting_client(test_client_2_name, fence,
1498+ [&](MockInputHandler& handler, mt::WaitCondition& events_received)
1499+ {
1500+ EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
1501+ EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
1502+ EXPECT_CALL(handler, handle_input(MotionEventWithPosition(1, 1))).Times(1)
1503+ .WillOnce(DoAll(SignalFence(&second_client_done_fence), mt::WakeUp(&events_received)));
1504+ });
1505+
1506+ launch_client_process(*client_config_1);
1507+ launch_client_process(*client_config_2);
1508 }
1509
1510=== modified file 'tests/unit-tests/client/input/test_android_input_receiver.cpp'
1511--- tests/unit-tests/client/input/test_android_input_receiver.cpp 2013-05-31 16:06:07 +0000
1512+++ tests/unit-tests/client/input/test_android_input_receiver.cpp 2013-11-07 00:22:14 +0000
1513@@ -17,8 +17,10 @@
1514 */
1515
1516 #include "src/shared/input/android/android_input_receiver.h"
1517+#include "mir/input/null_input_receiver_report.h"
1518 #include "mir_toolkit/event.h"
1519
1520+
1521 #include <androidfw/InputTransport.h>
1522
1523 #include <gmock/gmock.h>
1524@@ -27,7 +29,8 @@
1525 #include <unistd.h>
1526 #include <memory>
1527
1528-namespace mircva = mir::input::receiver::android;
1529+namespace mircv = mir::input::receiver;
1530+namespace mircva = mircv::android;
1531
1532 namespace droidinput = android;
1533
1534@@ -142,14 +145,14 @@
1535
1536 TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd)
1537 {
1538- mircva::InputReceiver receiver(client_fd);
1539+ mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
1540
1541 EXPECT_EQ(client_fd, receiver.fd());
1542 }
1543
1544 TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events)
1545 {
1546- mircva::InputReceiver receiver(client_fd);
1547+ mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
1548 TestingInputProducer producer(server_fd);
1549
1550 producer.produce_a_key_event();
1551@@ -165,7 +168,7 @@
1552
1553 TEST_F(AndroidInputReceiverSetup, receiver_handles_events)
1554 {
1555- mircva::InputReceiver receiver(client_fd);
1556+ mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
1557 TestingInputProducer producer(server_fd);
1558
1559 producer.produce_a_key_event();
1560@@ -181,7 +184,7 @@
1561
1562 TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events)
1563 {
1564- mircva::InputReceiver receiver(client_fd);
1565+ mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
1566 TestingInputProducer producer(server_fd);
1567
1568 // Produce 3 motion events before client handles any.
1569
1570=== modified file 'tests/unit-tests/client/input/test_android_input_receiver_thread.cpp'
1571--- tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2013-05-13 23:20:52 +0000
1572+++ tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2013-11-07 00:22:14 +0000
1573@@ -19,6 +19,8 @@
1574 #include "src/shared/input/android/android_input_receiver_thread.h"
1575 #include "src/shared/input/android/android_input_receiver.h"
1576
1577+#include "mir/input/null_input_receiver_report.h"
1578+
1579 #include "mir_toolkit/mir_client_library.h"
1580
1581 #include <gtest/gtest.h>
1582@@ -30,7 +32,8 @@
1583
1584 #include <fcntl.h>
1585
1586-namespace mircva = mir::input::receiver::android;
1587+namespace mircv = mir::input::receiver;
1588+namespace mircva = mircv::android;
1589
1590 namespace
1591 {
1592@@ -43,7 +46,7 @@
1593 struct MockInputReceiver : public mircva::InputReceiver
1594 {
1595 MockInputReceiver(int fd)
1596- : InputReceiver(fd)
1597+ : InputReceiver(fd, std::make_shared<mircv::NullInputReceiverReport>())
1598 {
1599 }
1600 MOCK_METHOD1(next_event, bool(MirEvent &));

Subscribers

People subscribed via source and target branches