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
=== modified file 'doc/component_reports.md'
--- doc/component_reports.md 2013-10-24 11:41:30 +0000
+++ doc/component_reports.md 2013-11-07 00:22:14 +0000
@@ -40,6 +40,7 @@
40Report | Handlers40Report | Handlers
41------------------- | --------41------------------- | --------
42rpc-report | log,lttng42rpc-report | log,lttng
43input-receiver | log
4344
44For example, to enable the logging RPC report, one should set the45For example, to enable the logging RPC report, one should set the
45`MIR_CLIENT_RPC_REPORT=log` environment variable.46`MIR_CLIENT_RPC_REPORT=log` environment variable.
4647
=== modified file 'include/shared/mir/input/input_platform.h'
--- include/shared/mir/input/input_platform.h 2013-05-13 23:20:52 +0000
+++ include/shared/mir/input/input_platform.h 2013-11-07 00:22:14 +0000
@@ -31,6 +31,7 @@
31namespace receiver31namespace receiver
32{32{
33class InputReceiverThread;33class InputReceiverThread;
34class InputReceiverReport;
3435
35// Interface for MirSurface to construct input dispatcher threads.36// Interface for MirSurface to construct input dispatcher threads.
36class InputPlatform37class InputPlatform
@@ -39,8 +40,9 @@
39 virtual ~InputPlatform() {}; 40 virtual ~InputPlatform() {};
4041
41 virtual std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback) = 0;42 virtual std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback) = 0;
42 43
43 static std::shared_ptr<InputPlatform> create();44 static std::shared_ptr<InputPlatform> create();
45 static std::shared_ptr<InputPlatform> create(std::shared_ptr<InputReceiverReport> const& report);
4446
45protected:47protected:
46 InputPlatform() = default;48 InputPlatform() = default;
4749
=== added file 'include/shared/mir/input/input_receiver_report.h'
--- include/shared/mir/input/input_receiver_report.h 1970-01-01 00:00:00 +0000
+++ include/shared/mir/input/input_receiver_report.h 2013-11-07 00:22:14 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_INPUT_RECEIVER_REPORT_H_
20#define MIR_CLIENT_INPUT_RECEIVER_REPORT_H_
21
22#include <mir_toolkit/event.h>
23
24namespace mir
25{
26namespace input
27{
28namespace receiver
29{
30
31class InputReceiverReport
32{
33public:
34 virtual ~InputReceiverReport() = default;
35
36 virtual void received_event(MirEvent const& event) = 0;
37
38protected:
39 InputReceiverReport() = default;
40 InputReceiverReport(InputReceiverReport const&) = delete;
41 InputReceiverReport& operator=(InputReceiverReport const&) = delete;
42};
43
44}
45}
46}
47
48#endif /* MIR_CLIENT_INPUT_RECEIVER_REPORT_H_ */
049
=== added file 'include/shared/mir/input/null_input_receiver_report.h'
--- include/shared/mir/input/null_input_receiver_report.h 1970-01-01 00:00:00 +0000
+++ include/shared/mir/input/null_input_receiver_report.h 2013-11-07 00:22:14 +0000
@@ -0,0 +1,46 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_
20#define MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_
21
22#include "mir/input/input_receiver_report.h"
23
24#include <mir_toolkit/event.h>
25
26namespace mir
27{
28namespace input
29{
30namespace receiver
31{
32
33class NullInputReceiverReport : public InputReceiverReport
34{
35public:
36 NullInputReceiverReport() = default;
37 virtual ~NullInputReceiverReport() = default;
38
39 void received_event(MirEvent const& /* event */) {}
40};
41
42}
43}
44}
45
46#endif /* MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_ */
047
=== modified file 'include/test/mir_test_framework/input_testing_server_configuration.h'
--- include/test/mir_test_framework/input_testing_server_configuration.h 2013-08-28 03:41:48 +0000
+++ include/test/mir_test_framework/input_testing_server_configuration.h 2013-11-07 00:22:14 +0000
@@ -65,9 +65,10 @@
65 std::shared_ptr<mir::input::InputConfiguration> the_input_configuration() override;65 std::shared_ptr<mir::input::InputConfiguration> the_input_configuration() override;
66 std::shared_ptr<mir::frontend::Shell> the_frontend_shell() override;66 std::shared_ptr<mir::frontend::Shell> the_frontend_shell() override;
6767
68 mir::input::android::FakeEventHub* fake_event_hub;
69
68protected:70protected:
69 virtual void inject_input() = 0;71 virtual void inject_input() = 0;
70 mir::input::android::FakeEventHub* fake_event_hub;
7172
72 void wait_until_client_appears(std::string const& surface_name);73 void wait_until_client_appears(std::string const& surface_name);
7374
7475
=== modified file 'src/client/CMakeLists.txt'
--- src/client/CMakeLists.txt 2013-10-21 16:02:28 +0000
+++ src/client/CMakeLists.txt 2013-11-07 00:22:14 +0000
@@ -29,6 +29,7 @@
29 mir_wait_handle.cpp29 mir_wait_handle.cpp
30 mir_surface.cpp30 mir_surface.cpp
31 logging/rpc_report.cpp31 logging/rpc_report.cpp
32 logging/input_receiver_report.cpp
32 default_connection_configuration.cpp33 default_connection_configuration.cpp
33 surface_map.cpp34 surface_map.cpp
34 lifecycle_control.cpp35 lifecycle_control.cpp
3536
=== modified file 'src/client/default_connection_configuration.cpp'
--- src/client/default_connection_configuration.cpp 2013-08-28 03:41:48 +0000
+++ src/client/default_connection_configuration.cpp 2013-11-07 00:22:14 +0000
@@ -24,7 +24,9 @@
24#include "mir/logging/dumb_console_logger.h"24#include "mir/logging/dumb_console_logger.h"
25#include "native_client_platform_factory.h"25#include "native_client_platform_factory.h"
26#include "mir/input/input_platform.h"26#include "mir/input/input_platform.h"
27#include "mir/input/null_input_receiver_report.h"
27#include "logging/rpc_report.h"28#include "logging/rpc_report.h"
29#include "logging/input_receiver_report.h"
28#include "lttng/rpc_report.h"30#include "lttng/rpc_report.h"
29#include "connection_surface_map.h"31#include "connection_surface_map.h"
30#include "lifecycle_control.h"32#include "lifecycle_control.h"
@@ -88,9 +90,9 @@
88mcl::DefaultConnectionConfiguration::the_input_platform()90mcl::DefaultConnectionConfiguration::the_input_platform()
89{91{
90 return input_platform(92 return input_platform(
91 []93 [this]
92 {94 {
93 return mir::input::receiver::InputPlatform::create();95 return mir::input::receiver::InputPlatform::create(the_input_receiver_report());
94 });96 });
95}97}
9698
@@ -118,6 +120,22 @@
118 });120 });
119}121}
120122
123std::shared_ptr<mir::input::receiver::InputReceiverReport>
124mcl::DefaultConnectionConfiguration::the_input_receiver_report()
125{
126 return input_receiver_report(
127 [this] () -> std::shared_ptr<mir::input::receiver::InputReceiverReport>
128 {
129 auto val_raw = getenv("MIR_CLIENT_INPUT_RECEIVER_REPORT");
130 std::string const val{val_raw ? val_raw : off_opt_val};
131
132 if (val == log_opt_val)
133 return std::make_shared<mcl::logging::InputReceiverReport>(the_logger());
134 else
135 return std::make_shared<mir::input::receiver::NullInputReceiverReport>();
136 });
137}
138
121std::shared_ptr<mcl::DisplayConfiguration> mcl::DefaultConnectionConfiguration::the_display_configuration()139std::shared_ptr<mcl::DisplayConfiguration> mcl::DefaultConnectionConfiguration::the_display_configuration()
122{140{
123 return display_configuration(141 return display_configuration(
124142
=== modified file 'src/client/default_connection_configuration.h'
--- src/client/default_connection_configuration.h 2013-08-28 03:41:48 +0000
+++ src/client/default_connection_configuration.h 2013-11-07 00:22:14 +0000
@@ -27,6 +27,13 @@
2727
28namespace mir28namespace mir
29{29{
30namespace input
31{
32namespace receiver
33{
34class InputReceiverReport;
35}
36}
30namespace client37namespace client
31{38{
3239
@@ -50,6 +57,7 @@
5057
51 virtual std::string the_socket_file();58 virtual std::string the_socket_file();
52 virtual std::shared_ptr<rpc::RpcReport> the_rpc_report();59 virtual std::shared_ptr<rpc::RpcReport> the_rpc_report();
60 virtual std::shared_ptr<input::receiver::InputReceiverReport> the_input_receiver_report();
5361
54protected:62protected:
55 CachedPtr<rpc::MirBasicRpcChannel> rpc_channel;63 CachedPtr<rpc::MirBasicRpcChannel> rpc_channel;
@@ -61,6 +69,7 @@
61 CachedPtr<LifecycleControl> lifecycle_control;69 CachedPtr<LifecycleControl> lifecycle_control;
6270
63 CachedPtr<rpc::RpcReport> rpc_report;71 CachedPtr<rpc::RpcReport> rpc_report;
72 CachedPtr<input::receiver::InputReceiverReport> input_receiver_report;
6473
65private:74private:
66 std::string const socket_file;75 std::string const socket_file;
6776
=== added file 'src/client/logging/input_receiver_report.cpp'
--- src/client/logging/input_receiver_report.cpp 1970-01-01 00:00:00 +0000
+++ src/client/logging/input_receiver_report.cpp 2013-11-07 00:22:14 +0000
@@ -0,0 +1,125 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "input_receiver_report.h"
20
21#include "mir/logging/logger.h"
22
23#include <boost/throw_exception.hpp>
24
25#include <sstream>
26#include <stdexcept>
27
28namespace ml = mir::logging;
29namespace mcll = mir::client::logging;
30
31namespace
32{
33std::string const component{"input-receiver"};
34}
35
36mcll::InputReceiverReport::InputReceiverReport(std::shared_ptr<ml::Logger> const& logger)
37 : logger{logger}
38{
39}
40
41namespace
42{
43
44static void format_key_event(std::stringstream &ss, MirKeyEvent const& ev)
45{
46 ss << "MirKeyEvent {" << std::endl;
47 ss << " device_id: " << ev.device_id << std::endl;
48 ss << " source_id: " << ev.source_id << std::endl;
49 ss << " action: " << ev.action << std::endl;
50 ss << " flags: " << ev.flags << std::endl;
51 ss << " modifiers: " << ev.modifiers << std::endl;
52 ss << " key_code: " << ev.key_code << std::endl;
53 ss << " scan_code: " << ev.scan_code << std::endl;
54 ss << " repeat_count: " << ev.repeat_count << std::endl;
55 ss << " down_time: " << ev.down_time << std::endl;
56 ss << " event_time: " << ev.event_time << std::endl;
57 ss << " is_system_key: " << ev.is_system_key << std::endl;
58 ss << "}";
59}
60static void format_motion_event(std::stringstream &ss, MirMotionEvent const& ev)
61{
62 ss << "MirMotionEvent{" << std::endl;
63 ss << " type: motion" << std::endl;
64 ss << " device_id: " << ev.device_id << std::endl;
65 ss << " source_id: " << ev.source_id << std::endl;
66 ss << " action: " << ev.action << std::endl;
67 ss << " flags: " << ev.flags << std::endl;
68 ss << " modifiers: " << ev.modifiers << std::endl;
69 ss << " edge_flags: " << ev.edge_flags << std::endl;
70 ss << " button_state: " << ev.button_state << std::endl;
71 ss << " x_offset: " << ev.x_offset << std::endl;
72 ss << " y_offset: " << ev.y_offset << std::endl;
73 ss << " x_precision: " << ev.x_precision << std::endl;
74 ss << " y_precision: " << ev.y_precision << std::endl;
75 ss << " down_time: " << ev.down_time << std::endl;
76 ss << " event_time: " << ev.event_time << std::endl;
77 ss << " pointer_count: " << ev.pointer_count << std::endl;
78 for (unsigned int i = 0; i < ev.pointer_count; i++)
79 {
80 ss << " pointer[" << i << "]{" << std::endl;
81 ss << " id: " << ev.pointer_coordinates[i].id << std::endl;
82 ss << " x: " << ev.pointer_coordinates[i].x << std::endl;
83 ss << " raw_x: " << ev.pointer_coordinates[i].raw_x << std::endl;
84 ss << " y: " << ev.pointer_coordinates[i].y << std::endl;
85 ss << " raw_y: " << ev.pointer_coordinates[i].raw_y << std::endl;
86 ss << " touch_major: " << ev.pointer_coordinates[i].touch_major << std::endl;
87 ss << " touch_minor: " << ev.pointer_coordinates[i].touch_minor << std::endl;
88 ss << " size: " << ev.pointer_coordinates[i].size << std::endl;
89 ss << " pressure: " << ev.pointer_coordinates[i].pressure << std::endl;
90 ss << " orientation: " << ev.pointer_coordinates[i].orientation << std::endl;
91 ss << " vscroll: " << ev.pointer_coordinates[i].vscroll << std::endl;
92 ss << " hscroll: " << ev.pointer_coordinates[i].hscroll << std::endl;
93 ss << " }" << std::endl;
94 }
95 ss << "}";
96}
97
98static void format_event(std::stringstream &ss, MirEvent const& ev)
99{
100 switch (ev.type)
101 {
102 case mir_event_type_key:
103 format_key_event(ss, ev.key);
104 break;
105 case mir_event_type_motion:
106 format_motion_event(ss, ev.motion);
107 break;
108 default:
109 BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected event type"));
110 }
111}
112
113}
114
115void mcll::InputReceiverReport::received_event(
116 MirEvent const& event)
117{
118 std::stringstream ss;
119
120 ss << "Received event:" << std::endl;
121
122 format_event(ss, event);
123
124 logger->log<ml::Logger::debug>(ss.str(), component);
125}
0126
=== added file 'src/client/logging/input_receiver_report.h'
--- src/client/logging/input_receiver_report.h 1970-01-01 00:00:00 +0000
+++ src/client/logging/input_receiver_report.h 2013-11-07 00:22:14 +0000
@@ -0,0 +1,54 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_
20#define MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_
21
22#include "mir/input/input_receiver_report.h"
23
24#include <memory>
25
26namespace mir
27{
28
29namespace logging
30{
31class Logger;
32}
33
34namespace client
35{
36namespace logging
37{
38
39class InputReceiverReport : public input::receiver::InputReceiverReport
40{
41public:
42 InputReceiverReport(std::shared_ptr<mir::logging::Logger> const& logger);
43
44 void received_event(MirEvent const& event) override;
45
46private:
47 std::shared_ptr<mir::logging::Logger> const logger;
48};
49
50}
51}
52}
53
54#endif /* MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_ */
055
=== modified file 'src/shared/input/android/android_input_platform.cpp'
--- src/shared/input/android/android_input_platform.cpp 2013-05-13 23:20:52 +0000
+++ src/shared/input/android/android_input_platform.cpp 2013-11-07 00:22:14 +0000
@@ -20,10 +20,13 @@
20#include "android_input_receiver.h"20#include "android_input_receiver.h"
21#include "android_input_receiver_thread.h"21#include "android_input_receiver_thread.h"
2222
23#include "mir/input/null_input_receiver_report.h"
24
23namespace mircv = mir::input::receiver;25namespace mircv = mir::input::receiver;
24namespace mircva = mircv::android;26namespace mircva = mircv::android;
2527
26mircva::AndroidInputPlatform::AndroidInputPlatform()28mircva::AndroidInputPlatform::AndroidInputPlatform(std::shared_ptr<mircv::InputReceiverReport> const& report)
29 : report(report)
27{30{
28}31}
2932
@@ -34,11 +37,16 @@
34std::shared_ptr<mircv::InputReceiverThread> mircva::AndroidInputPlatform::create_input_thread(37std::shared_ptr<mircv::InputReceiverThread> mircva::AndroidInputPlatform::create_input_thread(
35 int fd, std::function<void(MirEvent*)> const& callback)38 int fd, std::function<void(MirEvent*)> const& callback)
36{39{
37 auto receiver = std::make_shared<mircva::InputReceiver>(fd);40 auto receiver = std::make_shared<mircva::InputReceiver>(fd, report);
38 return std::make_shared<mircva::InputReceiverThread>(receiver, callback);41 return std::make_shared<mircva::InputReceiverThread>(receiver, callback);
39}42}
4043
41std::shared_ptr<mircv::InputPlatform> mircv::InputPlatform::create()44std::shared_ptr<mircv::InputPlatform> mircv::InputPlatform::create()
42{45{
43 return std::make_shared<mircva::AndroidInputPlatform>();46 return create(std::make_shared<mircv::NullInputReceiverReport>());
47}
48
49std::shared_ptr<mircv::InputPlatform> mircv::InputPlatform::create(std::shared_ptr<mircv::InputReceiverReport> const& report)
50{
51 return std::make_shared<mircva::AndroidInputPlatform>(report);
44}52}
4553
=== modified file 'src/shared/input/android/android_input_platform.h'
--- src/shared/input/android/android_input_platform.h 2013-05-13 23:20:52 +0000
+++ src/shared/input/android/android_input_platform.h 2013-11-07 00:22:14 +0000
@@ -34,7 +34,7 @@
34class AndroidInputPlatform : public InputPlatform34class AndroidInputPlatform : public InputPlatform
35{35{
36public:36public:
37 AndroidInputPlatform();37 AndroidInputPlatform(std::shared_ptr<InputReceiverReport> const& report);
38 virtual ~AndroidInputPlatform(); 38 virtual ~AndroidInputPlatform();
3939
40 std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback);40 std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback);
@@ -42,6 +42,9 @@
42protected:42protected:
43 AndroidInputPlatform(const AndroidInputPlatform&) = delete;43 AndroidInputPlatform(const AndroidInputPlatform&) = delete;
44 AndroidInputPlatform& operator=(const AndroidInputPlatform&) = delete;44 AndroidInputPlatform& operator=(const AndroidInputPlatform&) = delete;
45
46private:
47 std::shared_ptr<InputReceiverReport> const report;
45};48};
4649
47}50}
4851
=== modified file 'src/shared/input/android/android_input_receiver.cpp'
--- src/shared/input/android/android_input_receiver.cpp 2013-05-24 18:20:37 +0000
+++ src/shared/input/android/android_input_receiver.cpp 2013-11-07 00:22:14 +0000
@@ -19,6 +19,7 @@
19#include "android_input_receiver.h"19#include "android_input_receiver.h"
2020
21#include "mir/input/xkb_mapper.h"21#include "mir/input/xkb_mapper.h"
22#include "mir/input/input_receiver_report.h"
22#include "mir/input/android/android_input_lexicon.h"23#include "mir/input/android/android_input_lexicon.h"
2324
24#include <androidfw/InputTransport.h>25#include <androidfw/InputTransport.h>
@@ -29,8 +30,10 @@
2930
30namespace mia = mir::input::android;31namespace mia = mir::input::android;
3132
32mircva::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel)33mircva::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel,
34 std::shared_ptr<mircv::InputReceiverReport> const& report)
33 : input_channel(input_channel),35 : input_channel(input_channel),
36 report(report),
34 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),37 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
35 looper(new droidinput::Looper(true)),38 looper(new droidinput::Looper(true)),
36 fd_added(false),39 fd_added(false),
@@ -38,8 +41,10 @@
38{41{
39}42}
4043
41mircva::InputReceiver::InputReceiver(int fd)44mircva::InputReceiver::InputReceiver(int fd,
45 std::shared_ptr<mircv::InputReceiverReport> const& report)
42 : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)), 46 : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)),
47 report(report),
43 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),48 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
44 looper(new droidinput::Looper(true)),49 looper(new droidinput::Looper(true)),
45 fd_added(false),50 fd_added(false),
@@ -84,6 +89,8 @@
84 map_key_event(xkb_mapper, ev);89 map_key_event(xkb_mapper, ev);
8590
86 input_consumer->sendFinishedSignal(event_sequence_id, true);91 input_consumer->sendFinishedSignal(event_sequence_id, true);
92
93 report->received_event(ev);
8794
88 return true;95 return true;
89 }96 }
9097
=== modified file 'src/shared/input/android/android_input_receiver.h'
--- src/shared/input/android/android_input_receiver.h 2013-05-24 18:20:37 +0000
+++ src/shared/input/android/android_input_receiver.h 2013-11-07 00:22:14 +0000
@@ -43,6 +43,7 @@
43namespace receiver43namespace receiver
44{44{
45class XKBMapper;45class XKBMapper;
46class InputReceiverReport;
4647
47namespace android48namespace android
48{49{
@@ -51,8 +52,10 @@
51class InputReceiver52class InputReceiver
52{53{
53public:54public:
54 InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel);55 InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel,
55 InputReceiver(int fd);56 std::shared_ptr<InputReceiverReport> const& report);
57 InputReceiver(int fd,
58 std::shared_ptr<InputReceiverReport> const& report);
5659
57 virtual ~InputReceiver();60 virtual ~InputReceiver();
58 int fd() const;61 int fd() const;
@@ -71,6 +74,8 @@
7174
72private:75private:
73 droidinput::sp<droidinput::InputChannel> input_channel;76 droidinput::sp<droidinput::InputChannel> input_channel;
77 std::shared_ptr<InputReceiverReport> const report;
78
74 std::shared_ptr<droidinput::InputConsumer> input_consumer;79 std::shared_ptr<droidinput::InputConsumer> input_consumer;
75 droidinput::PreallocatedInputEventFactory event_factory;80 droidinput::PreallocatedInputEventFactory event_factory;
76 droidinput::sp<droidinput::Looper> looper;81 droidinput::sp<droidinput::Looper> looper;
7782
=== modified file 'tests/acceptance-tests/test_client_input.cpp'
--- tests/acceptance-tests/test_client_input.cpp 2013-10-28 21:41:27 +0000
+++ tests/acceptance-tests/test_client_input.cpp 2013-11-07 00:22:14 +0000
@@ -248,6 +248,16 @@
248 return true;248 return true;
249}249}
250250
251MATCHER(HoverMoveEvent, "")
252{
253 if (arg->type != mir_event_type_motion)
254 return false;
255 if (arg->motion.action != mir_motion_action_hover_move)
256 return false;
257
258 return true;
259}
260
251MATCHER_P2(ButtonDownEvent, x, y, "")261MATCHER_P2(ButtonDownEvent, x, y, "")
252{262{
253 if (arg->type != mir_event_type_motion)263 if (arg->type != mir_event_type_motion)
@@ -302,194 +312,6 @@
302312
303}313}
304314
305
306using TestClientInput = BespokeDisplayServerTestFixture;
307
308TEST_F(TestClientInput, clients_receive_key_input)
309{
310 using namespace ::testing;
311
312 int const num_events_produced = 3;
313 static std::string const test_client_name = "1";
314
315 mtf::CrossProcessSync fence;
316
317 struct ServerConfiguration : mtf::InputTestingServerConfiguration
318 {
319 mtf::CrossProcessSync input_cb_setup_fence;
320
321 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
322 : input_cb_setup_fence(input_cb_setup_fence)
323 {
324 }
325
326 void inject_input()
327 {
328 wait_until_client_appears(test_client_name);
329 input_cb_setup_fence.wait_for_signal_ready_for();
330
331 for (int i = 0; i < num_events_produced; i++)
332 fake_event_hub->synthesize_event(mis::a_key_down_event()
333 .of_scancode(KEY_ENTER));
334 }
335 } server_config(fence);
336 launch_server_process(server_config);
337
338 struct KeyReceivingClient : InputClient
339 {
340 KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
341 void expect_input(mt::WaitCondition& events_received) override
342 {
343 using namespace ::testing;
344 InSequence seq;
345
346 EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(2);
347 EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(1)
348 .WillOnce(mt::WakeUp(&events_received));
349 }
350 } client_config(fence);
351 launch_client_process(client_config);
352}
353
354TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
355{
356 using namespace ::testing;
357 static std::string const test_client_name = "1";
358 mtf::CrossProcessSync fence;
359
360 struct ServerConfiguration : mtf::InputTestingServerConfiguration
361 {
362 mtf::CrossProcessSync input_cb_setup_fence;
363
364 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
365 : input_cb_setup_fence(input_cb_setup_fence)
366 {
367 }
368
369 void inject_input()
370 {
371 wait_until_client_appears(test_client_name);
372 input_cb_setup_fence.wait_for_signal_ready_for();
373
374 fake_event_hub->synthesize_event(mis::a_key_down_event()
375 .of_scancode(KEY_LEFTSHIFT));
376 fake_event_hub->synthesize_event(mis::a_key_down_event()
377 .of_scancode(KEY_4));
378
379 }
380 } server_config{fence};
381 launch_server_process(server_config);
382
383 struct KeyReceivingClient : InputClient
384 {
385 KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
386
387 void expect_input(mt::WaitCondition& events_received) override
388 {
389 using namespace ::testing;
390
391 InSequence seq;
392 EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1);
393 EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1)
394 .WillOnce(mt::WakeUp(&events_received));
395 }
396 } client_config{fence};
397 launch_client_process(client_config);
398}
399
400TEST_F(TestClientInput, clients_receive_motion_inside_window)
401{
402 using namespace ::testing;
403 static std::string const test_client_name = "1";
404 mtf::CrossProcessSync fence;
405
406 struct ServerConfiguration : public mtf::InputTestingServerConfiguration
407 {
408 mtf::CrossProcessSync input_cb_setup_fence;
409
410 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
411 : input_cb_setup_fence(input_cb_setup_fence)
412 {
413 }
414
415 void inject_input()
416 {
417 wait_until_client_appears(test_client_name);
418 input_cb_setup_fence.wait_for_signal_ready_for();
419
420 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1,
421 InputClient::surface_height - 1));
422 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2));
423 }
424 } server_config{fence};
425 launch_server_process(server_config);
426
427 struct MotionReceivingClient : InputClient
428 {
429 MotionReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
430
431 void expect_input(mt::WaitCondition& events_received) override
432 {
433 using namespace ::testing;
434
435 InSequence seq;
436
437 // We should see the cursor enter
438 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);
439 EXPECT_CALL(*handler, handle_input(
440 MotionEventWithPosition(InputClient::surface_width - 1,
441 InputClient::surface_height - 1))).Times(1)
442 .WillOnce(mt::WakeUp(&events_received));
443 // But we should not receive an event for the second movement outside of our surface!
444 }
445 } client_config{fence};
446 launch_client_process(client_config);
447}
448
449TEST_F(TestClientInput, clients_receive_button_events_inside_window)
450{
451 using namespace ::testing;
452
453 static std::string const test_client_name = "1";
454 mtf::CrossProcessSync fence;
455
456 struct ServerConfiguration : public mtf::InputTestingServerConfiguration
457 {
458 mtf::CrossProcessSync input_cb_setup_fence;
459
460 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence)
461 : input_cb_setup_fence(input_cb_setup_fence)
462 {
463 }
464
465 void inject_input()
466 {
467 wait_until_client_appears(test_client_name);
468 input_cb_setup_fence.wait_for_signal_ready_for();
469
470 fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
471 }
472 } server_config{fence};
473 launch_server_process(server_config);
474
475 struct ButtonReceivingClient : InputClient
476 {
477 ButtonReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
478
479 void expect_input(mt::WaitCondition& events_received) override
480 {
481 using namespace ::testing;
482
483 InSequence seq;
484
485 // The cursor starts at (0, 0).
486 EXPECT_CALL(*handler, handle_input(ButtonDownEvent(0, 0))).Times(1)
487 .WillOnce(mt::WakeUp(&events_received));
488 }
489 } client_config{fence};
490 launch_client_process(client_config);
491}
492
493namespace315namespace
494{316{
495typedef std::map<std::string, geom::Rectangle> GeometryMap;317typedef std::map<std::string, geom::Rectangle> GeometryMap;
@@ -497,34 +319,251 @@
497319
498struct StaticPlacementStrategy : public msh::PlacementStrategy320struct StaticPlacementStrategy : public msh::PlacementStrategy
499{321{
500 StaticPlacementStrategy(GeometryMap const& positions,322 StaticPlacementStrategy(std::shared_ptr<msh::PlacementStrategy> const& underlying_strategy,
323 GeometryMap const& positions,
501 DepthMap const& depths)324 DepthMap const& depths)
502 : surface_geometry_by_name(positions),325 : underlying_strategy(underlying_strategy),
326 surface_geometry_by_name(positions),
503 surface_depths_by_name(depths)327 surface_depths_by_name(depths)
504 {328 {
505 }329 }
506330
507 StaticPlacementStrategy(GeometryMap const& positions)331 StaticPlacementStrategy(std::shared_ptr<msh::PlacementStrategy> const& underlying_strategy,
508 : StaticPlacementStrategy(positions, DepthMap())332 GeometryMap const& positions)
333 : StaticPlacementStrategy(underlying_strategy, positions, DepthMap())
509 {334 {
510 }335 }
511336
512 msh::SurfaceCreationParameters place(msh::Session const&, msh::SurfaceCreationParameters const& request_parameters)337 msh::SurfaceCreationParameters place(msh::Session const& session, msh::SurfaceCreationParameters const& request_parameters)
513 {338 {
514 auto placed = request_parameters;339 auto placed = request_parameters;
515 auto const& name = request_parameters.name;340 auto const& name = request_parameters.name;
516 auto geometry = surface_geometry_by_name[name];341
517342 auto it = surface_geometry_by_name.find(name);
518 placed.top_left = geometry.top_left;343 if (it != surface_geometry_by_name.end())
519 placed.size = geometry.size;344 {
345 auto const& geometry = it->second;
346 placed.top_left = geometry.top_left;
347 placed.size = geometry.size;
348 }
349 else
350 {
351 placed = underlying_strategy->place(session, placed);
352 }
520 placed.depth = surface_depths_by_name[name];353 placed.depth = surface_depths_by_name[name];
521 354
522 return placed;355 return placed;
523 }356 }
357
358 std::shared_ptr<msh::PlacementStrategy> const underlying_strategy;
524 GeometryMap surface_geometry_by_name;359 GeometryMap surface_geometry_by_name;
525 DepthMap surface_depths_by_name;360 DepthMap surface_depths_by_name;
526};361};
527362
363std::shared_ptr<mtf::InputTestingServerConfiguration>
364make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence,
365 int number_of_clients,
366 std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events,
367 GeometryMap const& client_geometry_map, DepthMap const& client_depth_map)
368{
369 struct ServerConfiguration : mtf::InputTestingServerConfiguration
370 {
371 mtf::CrossProcessSync input_cb_setup_fence;
372 int const number_of_clients;
373 std::function<void(mtf::InputTestingServerConfiguration& server)> const produce_events;
374 GeometryMap const client_geometry;
375 DepthMap const client_depth;
376
377 ServerConfiguration(mtf::CrossProcessSync const& input_cb_setup_fence, int number_of_clients,
378 std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events,
379 GeometryMap const& client_geometry, DepthMap const& client_depth)
380 : input_cb_setup_fence(input_cb_setup_fence),
381 number_of_clients(number_of_clients),
382 produce_events(produce_events),
383 client_geometry(client_geometry),
384 client_depth(client_depth)
385 {
386 }
387
388 std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
389 {
390 return std::make_shared<StaticPlacementStrategy>(InputTestingServerConfiguration::the_shell_placement_strategy(),
391 client_geometry, client_depth);
392 }
393
394 void inject_input()
395 {
396 for (int i = 1; i < number_of_clients + 1; i++)
397 EXPECT_EQ(i, input_cb_setup_fence.wait_for_signal_ready_for());
398 produce_events(*this);
399 }
400 };
401 return std::make_shared<ServerConfiguration>(client_ready_fence, number_of_clients,
402 produce_events, client_geometry_map, client_depth_map);
403}
404
405std::shared_ptr<mtf::InputTestingServerConfiguration>
406make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence, int number_of_clients,
407 std::function<void(mtf::InputTestingServerConfiguration& server)> const& produce_events)
408{
409 return make_event_producing_server(client_ready_fence, number_of_clients,
410 produce_events, GeometryMap(), DepthMap());
411}
412
413std::shared_ptr<InputClient>
414make_event_expecting_client(std::string const& client_name, mtf::CrossProcessSync const& client_ready_fence,
415 std::function<void(MockInputHandler &, mt::WaitCondition&)> const& expect_input)
416{
417 struct EventReceivingClient : InputClient
418 {
419 std::function<void(MockInputHandler&, mt::WaitCondition&)> const expect_cb;
420
421 EventReceivingClient(mtf::CrossProcessSync const& client_ready_fence, std::string const& client_name,
422 std::function<void(MockInputHandler&, mt::WaitCondition&)> const& expect_cb)
423 : InputClient(client_ready_fence, client_name),
424 expect_cb(expect_cb)
425 {
426 }
427 void expect_input(mt::WaitCondition& events_received) override
428 {
429 expect_cb(*handler, events_received);
430 }
431 };
432 return std::make_shared<EventReceivingClient>(client_ready_fence, client_name, expect_input);
433}
434
435std::shared_ptr<InputClient>
436make_event_expecting_client(mtf::CrossProcessSync const& client_ready_fence,
437 std::function<void(MockInputHandler &, mt::WaitCondition&)> const& expect_input)
438{
439 return make_event_expecting_client("input-test-client", client_ready_fence, expect_input);
440}
441
442}
443
444
445using TestClientInput = BespokeDisplayServerTestFixture;
446
447TEST_F(TestClientInput, clients_receive_key_input)
448{
449 using namespace ::testing;
450
451 static std::string const test_client_name = "1";
452
453 mtf::CrossProcessSync fence;
454
455 auto server_config = make_event_producing_server(fence, 1,
456 [&](mtf::InputTestingServerConfiguration& server)
457 {
458 int const num_events_produced = 3;
459
460 for (int i = 0; i < num_events_produced; i++)
461 server.fake_event_hub->synthesize_event(mis::a_key_down_event()
462 .of_scancode(KEY_ENTER));
463 });
464 launch_server_process(*server_config);
465
466 auto client_config = make_event_expecting_client(fence,
467 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
468 {
469 using namespace ::testing;
470 InSequence seq;
471
472 EXPECT_CALL(handler, handle_input(KeyDownEvent())).Times(2);
473 EXPECT_CALL(handler, handle_input(KeyDownEvent())).Times(1)
474 .WillOnce(mt::WakeUp(&events_received));
475
476 });
477 launch_client_process(*client_config);
478}
479
480TEST_F(TestClientInput, clients_receive_us_english_mapped_keys)
481{
482 using namespace ::testing;
483 static std::string const test_client_name = "1";
484 mtf::CrossProcessSync fence;
485
486 auto server_config = make_event_producing_server(fence, 1,
487 [&](mtf::InputTestingServerConfiguration& server)
488 {
489 server.fake_event_hub->synthesize_event(mis::a_key_down_event()
490 .of_scancode(KEY_LEFTSHIFT));
491 server.fake_event_hub->synthesize_event(mis::a_key_down_event()
492 .of_scancode(KEY_4));
493 });
494 launch_server_process(*server_config);
495
496 auto client_config = make_event_expecting_client(fence,
497 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
498 {
499 using namespace ::testing;
500 InSequence seq;
501
502 EXPECT_CALL(handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1);
503 EXPECT_CALL(handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1)
504 .WillOnce(mt::WakeUp(&events_received));
505 });
506 launch_client_process(*client_config);
507}
508
509TEST_F(TestClientInput, clients_receive_motion_inside_window)
510{
511 using namespace ::testing;
512 static std::string const test_client_name = "1";
513 mtf::CrossProcessSync fence;
514
515 auto server_config = make_event_producing_server(fence, 1,
516 [&](mtf::InputTestingServerConfiguration& server)
517 {
518 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1,
519 InputClient::surface_height - 1));
520 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2));
521 });
522 launch_server_process(*server_config);
523
524 auto client_config = make_event_expecting_client(fence,
525 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
526 {
527 using namespace ::testing;
528 InSequence seq;
529
530 // We should see the cursor enter
531 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(1);
532 EXPECT_CALL(handler, handle_input(
533 MotionEventWithPosition(InputClient::surface_width - 1,
534 InputClient::surface_height - 1))).Times(1)
535 .WillOnce(mt::WakeUp(&events_received));
536 // But we should not receive an event for the second movement outside of our surface!
537 });
538 launch_client_process(*client_config);
539}
540
541TEST_F(TestClientInput, clients_receive_button_events_inside_window)
542{
543 using namespace ::testing;
544
545 static std::string const test_client_name = "1";
546 mtf::CrossProcessSync fence;
547
548 auto server_config = make_event_producing_server(fence, 1,
549 [&](mtf::InputTestingServerConfiguration& server)
550 {
551 server.fake_event_hub->synthesize_event(mis::a_button_down_event()
552 .of_button(BTN_LEFT).with_action(mis::EventAction::Down));
553 });
554 launch_server_process(*server_config);
555
556 auto client_config = make_event_expecting_client(fence,
557 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
558 {
559 using namespace ::testing;
560 InSequence seq;
561
562 // The cursor starts at (0, 0).
563 EXPECT_CALL(handler, handle_input(ButtonDownEvent(0, 0))).Times(1)
564 .WillOnce(mt::WakeUp(&events_received));
565 });
566 launch_client_process(*client_config);
528}567}
529568
530TEST_F(TestClientInput, multiple_clients_receive_motion_inside_windows)569TEST_F(TestClientInput, multiple_clients_receive_motion_inside_windows)
@@ -539,77 +578,42 @@
539 static std::string const test_client_2 = "2";578 static std::string const test_client_2 = "2";
540 mtf::CrossProcessSync fence;579 mtf::CrossProcessSync fence;
541580
542 struct ServerConfiguration : mtf::InputTestingServerConfiguration581 static GeometryMap positions;
543 {582 positions[test_client_1] = geom::Rectangle{geom::Point{0, 0},
544 mtf::CrossProcessSync input_cb_setup_fence;583 geom::Size{client_width, client_height}};
545584 positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2},
546 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 585 geom::Size{client_width, client_height}};
547 : input_cb_setup_fence(input_cb_setup_fence)586
548 {587 auto server_config = make_event_producing_server(fence, 2,
549 }588 [&](mtf::InputTestingServerConfiguration& server)
550589 {
551 std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
552 {
553 static GeometryMap positions;
554 positions[test_client_1] = geom::Rectangle{geom::Point{0, 0},
555 geom::Size{client_width, client_height}};
556 positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2},
557 geom::Size{client_width, client_height}};
558
559 return std::make_shared<StaticPlacementStrategy>(positions);
560 }
561
562 void inject_input() override
563 {
564 wait_until_client_appears(test_client_1);
565 EXPECT_EQ(1, input_cb_setup_fence.wait_for_signal_ready_for());
566 wait_until_client_appears(test_client_2);
567 EXPECT_EQ(2, input_cb_setup_fence.wait_for_signal_ready_for());
568
569 // In the bounds of the first surface590 // In the bounds of the first surface
570 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1));591 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1));
571 // In the bounds of the second surface592 // In the bounds of the second surface
572 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2));593 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2));
573 }594 }, positions, DepthMap());
574 } server_config{fence};595 launch_server_process(*server_config);
575 596
576 launch_server_process(server_config);597 auto client_1 = make_event_expecting_client(test_client_1, fence,
577 598 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
578 struct InputClientOne : InputClient599 {
579 {600 InSequence seq;
580 InputClientOne(const mtf::CrossProcessSync& fence)601 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(1);
581 : InputClient(fence, test_client_1)602 EXPECT_CALL(handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1);
582 {603 EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(1)
583 }604 .WillOnce(mt::WakeUp(&events_received));
584 605 });
585 void expect_input(mt::WaitCondition& events_received) override606 auto client_2 = make_event_expecting_client(test_client_2, fence,
586 {607 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
587 InSequence seq;608 {
588 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);609 InSequence seq;
589 EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1);610 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(1);
590 EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(1)611 EXPECT_CALL(handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1)
591 .WillOnce(mt::WakeUp(&events_received));612 .WillOnce(mt::WakeUp(&events_received));
592 }613 });
593 } client_1{fence};614
594615 launch_client_process(*client_1);
595 struct InputClientTwo : InputClient616 launch_client_process(*client_2);
596 {
597 InputClientTwo(const mtf::CrossProcessSync& fence)
598 : InputClient(fence, test_client_2)
599 {
600 }
601
602 void expect_input(mt::WaitCondition& events_received) override
603 {
604 InSequence seq;
605 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);
606 EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1)
607 .WillOnce(mt::WakeUp(&events_received));
608 }
609 } client_2{fence};
610
611 launch_client_process(client_1);
612 launch_client_process(client_2);
613}617}
614618
615namespace619namespace
@@ -639,6 +643,7 @@
639 std::vector<geom::Rectangle> const input_rectangles;643 std::vector<geom::Rectangle> const input_rectangles;
640};644};
641}645}
646
642TEST_F(TestClientInput, clients_do_not_receive_motion_outside_input_region)647TEST_F(TestClientInput, clients_do_not_receive_motion_outside_input_region)
643{648{
644 using namespace ::testing;649 using namespace ::testing;
@@ -670,7 +675,7 @@
670 static GeometryMap positions;675 static GeometryMap positions;
671 positions[test_client_name] = screen_geometry;676 positions[test_client_name] = screen_geometry;
672 677
673 return std::make_shared<StaticPlacementStrategy>(positions);678 return std::make_shared<StaticPlacementStrategy>(InputTestingServerConfiguration::the_shell_placement_strategy(), positions);
674 }679 }
675 std::shared_ptr<msh::SurfaceFactory> the_shell_surface_factory() override680 std::shared_ptr<msh::SurfaceFactory> the_shell_surface_factory() override
676 {681 {
@@ -697,35 +702,26 @@
697 fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));702 fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
698 }703 }
699 } server_config{fence};704 } server_config{fence};
700
701 launch_server_process(server_config);705 launch_server_process(server_config);
702706
703 struct ClientConfig : InputClient707 auto client_config = make_event_expecting_client(test_client_name, fence,
704 {708 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
705 ClientConfig(const mtf::CrossProcessSync& fence)709 {
706 : InputClient(fence, test_client_name)710 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
707 {711 EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
708 }712 EXPECT_CALL(handler, handle_input(MovementEvent())).Times(AnyNumber());
709
710 void expect_input(mt::WaitCondition& events_received) override
711 {
712
713 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
714 EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
715 EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber());
716713
717 {714 {
718 // We should see two of the three button pairs.715 // We should see two of the three button pairs.
719 InSequence seq;716 InSequence seq;
720 EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1);717 EXPECT_CALL(handler, handle_input(ButtonDownEvent(1, 1))).Times(1);
721 EXPECT_CALL(*handler, handle_input(ButtonUpEvent(1, 1))).Times(1);718 EXPECT_CALL(handler, handle_input(ButtonUpEvent(1, 1))).Times(1);
722 EXPECT_CALL(*handler, handle_input(ButtonDownEvent(99, 99))).Times(1);719 EXPECT_CALL(handler, handle_input(ButtonDownEvent(99, 99))).Times(1);
723 EXPECT_CALL(*handler, handle_input(ButtonUpEvent(99, 99))).Times(1)720 EXPECT_CALL(handler, handle_input(ButtonUpEvent(99, 99))).Times(1)
724 .WillOnce(mt::WakeUp(&events_received));721 .WillOnce(mt::WakeUp(&events_received));
725 }722 }
726 }723 });
727 } client_config{fence};724 launch_client_process(*client_config);
728 launch_client_process(client_config);
729}725}
730726
731TEST_F(TestClientInput, surfaces_obscure_motion_events_by_stacking)727TEST_F(TestClientInput, surfaces_obscure_motion_events_by_stacking)
@@ -742,98 +738,62 @@
742 static geom::Rectangle const screen_geometry{geom::Point{0, 0},738 static geom::Rectangle const screen_geometry{geom::Point{0, 0},
743 geom::Size{screen_width, screen_height}};739 geom::Size{screen_width, screen_height}};
744740
745 struct ServerConfiguration : mtf::InputTestingServerConfiguration741 static GeometryMap positions;
746 {742 positions[test_client_name_1] = screen_geometry;
747 mtf::CrossProcessSync input_cb_setup_fence;743
748744 auto smaller_geometry = screen_geometry;
749 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 745 smaller_geometry.size.width = geom::Width{screen_width/2};
750 : input_cb_setup_fence(input_cb_setup_fence)746 positions[test_client_name_2] = smaller_geometry;
751 {747
752 }748 static DepthMap depths;
753749 depths[test_client_name_1] = ms::DepthId{0};
754 std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override750 depths[test_client_name_2] = ms::DepthId{1};
755 {751
756 static GeometryMap positions;752 auto server_config = make_event_producing_server(fence, 2,
757 positions[test_client_name_1] = screen_geometry;753 [&](mtf::InputTestingServerConfiguration& server)
758 754 {
759 auto smaller_geometry = screen_geometry;
760 smaller_geometry.size.width = geom::Width{screen_width/2};
761 positions[test_client_name_2] = smaller_geometry;
762
763 static DepthMap depths;
764 depths[test_client_name_1] = ms::DepthId{0};
765 depths[test_client_name_2] = ms::DepthId{1};
766
767 return std::make_shared<StaticPlacementStrategy>(positions, depths);
768 }
769
770 void inject_input() override
771 {
772 wait_until_client_appears(test_client_name_1);
773 input_cb_setup_fence.wait_for_signal_ready_for();
774 wait_until_client_appears(test_client_name_2);
775 input_cb_setup_fence.wait_for_signal_ready_for();
776
777 // First we will move the cursor in to the region where client 2 obscures client 1755 // First we will move the cursor in to the region where client 2 obscures client 1
778 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1));756 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1));
779 fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));757 server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
780 fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));758 server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
781 // Now we move to the unobscured region of client 1759 // Now we move to the unobscured region of client 1
782 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0));760 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0));
783 fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));761 server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
784 fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));762 server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
785 }763 }, positions, depths);
786 } server_config{fence};764 launch_server_process(*server_config);
787 765
788 launch_server_process(server_config);766 auto client_config_1 = make_event_expecting_client(test_client_name_1, fence,
789767 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
790 struct ClientConfigOne : InputClient768 {
791 {769 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
792 ClientConfigOne(const mtf::CrossProcessSync& fence)770 EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
793 : InputClient(fence, test_client_name_1)771 EXPECT_CALL(handler, handle_input(MovementEvent())).Times(AnyNumber());
794 {
795 }
796
797 void expect_input(mt::WaitCondition& events_received) override
798 {
799 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
800 EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
801 EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber());
802
803 {772 {
804 // We should only see one button event sequence.773 // We should only see one button event sequence.
805 InSequence seq;774 InSequence seq;
806 EXPECT_CALL(*handler, handle_input(ButtonDownEvent(51, 1))).Times(1);775 EXPECT_CALL(handler, handle_input(ButtonDownEvent(51, 1))).Times(1);
807 EXPECT_CALL(*handler, handle_input(ButtonUpEvent(51, 1))).Times(1)776 EXPECT_CALL(handler, handle_input(ButtonUpEvent(51, 1))).Times(1)
808 .WillOnce(mt::WakeUp(&events_received));777 .WillOnce(mt::WakeUp(&events_received));
809 }778 }
810 }779 });
811 } client_config_1{fence};780 auto client_config_2 = make_event_expecting_client(test_client_name_2, fence,
812 launch_client_process(client_config_1);781 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
813782 {
814 struct ClientConfigTwo : InputClient783 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
815 {784 EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
816 ClientConfigTwo(const mtf::CrossProcessSync& fence)785 EXPECT_CALL(handler, handle_input(MovementEvent())).Times(AnyNumber());
817 : InputClient(fence, test_client_name_2)
818 {
819 }
820
821 void expect_input(mt::WaitCondition& events_received) override
822 {
823 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
824 EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
825 EXPECT_CALL(*handler, handle_input(MovementEvent())).Times(AnyNumber());
826
827 {786 {
828 // Likewise we should only see one button sequence.787 // Likewise we should only see one button sequence.
829 InSequence seq;788 InSequence seq;
830 EXPECT_CALL(*handler, handle_input(ButtonDownEvent(1, 1))).Times(1);789 EXPECT_CALL(handler, handle_input(ButtonDownEvent(1, 1))).Times(1);
831 EXPECT_CALL(*handler, handle_input(ButtonUpEvent(1, 1))).Times(1)790 EXPECT_CALL(handler, handle_input(ButtonUpEvent(1, 1))).Times(1)
832 .WillOnce(mt::WakeUp(&events_received));791 .WillOnce(mt::WakeUp(&events_received));
833 }792 }
834 }793 });
835 } client_config_2{fence};794
836 launch_client_process(client_config_2);795 launch_client_process(*client_config_1);
796 launch_client_process(*client_config_2);
837}797}
838798
839namespace799namespace
@@ -853,93 +813,48 @@
853 static std::string const test_client_name = "1";813 static std::string const test_client_name = "1";
854 static std::string const test_client_2_name = "2";814 static std::string const test_client_2_name = "2";
855 mtf::CrossProcessSync fence, first_client_ready_fence, second_client_done_fence;815 mtf::CrossProcessSync fence, first_client_ready_fence, second_client_done_fence;
856816
857 struct ServerConfiguration : public mtf::InputTestingServerConfiguration817 static DepthMap depths;
858 {818 depths[test_client_name] = ms::DepthId{0};
859 mtf::CrossProcessSync input_cb_setup_fence;819 depths[test_client_2_name] = ms::DepthId{1};
860 mtf::CrossProcessSync second_client_done_fence;820
861821 auto server_config = make_event_producing_server(fence, 2,
862 ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence,822 [&](mtf::InputTestingServerConfiguration& server)
863 const mtf::CrossProcessSync& second_client_done_fence) 823 {
864 : input_cb_setup_fence(input_cb_setup_fence),
865 second_client_done_fence(second_client_done_fence)
866 {
867 }
868
869 void hide_session_by_name(std::string const& session_name)
870 {
871 the_shell_session_container()->for_each([&](std::shared_ptr<msh::Session> const& session) -> void
872 {
873 if (session->name() == session_name)
874 session->hide();
875 });
876 }
877
878 void inject_input()
879 {
880 wait_until_client_appears(test_client_name);
881 wait_until_client_appears(test_client_2_name);
882 input_cb_setup_fence.wait_for_signal_ready_for();
883
884 // We send one event and then hide the surface on top before sending the next. 824 // We send one event and then hide the surface on top before sending the next.
885 // So we expect each of the two surfaces to receive one event pair.825 // So we expect each of the two surfaces to receive one even
886 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));826 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));
887
888 // We use a fence to ensure we do not hide the client827 // We use a fence to ensure we do not hide the client
889 // before event dispatch occurs828 // before event dispatch occurs
890 second_client_done_fence.wait_for_signal_ready_for();829 second_client_done_fence.wait_for_signal_ready_for();
891 hide_session_by_name(test_client_2_name);830
892831 server.the_shell_session_container()->for_each([&](std::shared_ptr<msh::Session> const& session) -> void
893 fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));832 {
894 }833 if (session->name() == test_client_2_name)
895 } server_config{fence, second_client_done_fence};834 session->hide();
896 launch_server_process(server_config);835 });
897 836
898 struct ButtonClientOne : InputClient837 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1));
899 {838 }, GeometryMap(), depths);
900 ButtonClientOne(const mtf::CrossProcessSync& fence)839 launch_server_process(*server_config);
901 : InputClient(fence, test_client_name)840
902 {841 auto client_config_1 = make_event_expecting_client(test_client_name, fence,
903 }842 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
904 843 {
905 void expect_input(mt::WaitCondition& events_received) override844 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
906 {845 EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
907 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());846 EXPECT_CALL(handler, handle_input(MotionEventWithPosition(2, 2))).Times(1)
908 EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
909 EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(2, 2))).Times(1)
910 .WillOnce(mt::WakeUp(&events_received));847 .WillOnce(mt::WakeUp(&events_received));
911 }848 });
912 } client_1{first_client_ready_fence};849 auto client_config_2 = make_event_expecting_client(test_client_2_name, fence,
913 struct ButtonClientTwo : InputClient850 [&](MockInputHandler& handler, mt::WaitCondition& events_received)
914 {851 {
915 mtf::CrossProcessSync first_client_ready;852 EXPECT_CALL(handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
916 mtf::CrossProcessSync done_fence;853 EXPECT_CALL(handler, handle_input(HoverExitEvent())).Times(AnyNumber());
917854 EXPECT_CALL(handler, handle_input(MotionEventWithPosition(1, 1))).Times(1)
918 ButtonClientTwo(mtf::CrossProcessSync const& fence, mtf::CrossProcessSync const& first_client_ready,855 .WillOnce(DoAll(SignalFence(&second_client_done_fence), mt::WakeUp(&events_received)));
919 mtf::CrossProcessSync const& done_fence) 856 });
920 : InputClient(fence, test_client_2_name),857
921 first_client_ready(first_client_ready),858 launch_client_process(*client_config_1);
922 done_fence(done_fence)859 launch_client_process(*client_config_2);
923 {
924 }
925 void exec()
926 {
927 // Ensure we stack on top of the first client
928 first_client_ready.wait_for_signal_ready_for();
929 InputClient::exec();
930 }
931
932 void expect_input(mt::WaitCondition& events_received) override
933 {
934 EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(AnyNumber());
935 EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(AnyNumber());
936 EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(1, 1))).Times(1)
937 .WillOnce(DoAll(SignalFence(&done_fence), mt::WakeUp(&events_received)));
938 }
939 } client_2{fence, first_client_ready_fence, second_client_done_fence};
940
941 // Client 2 is launched second so will be the first to receive input
942
943 launch_client_process(client_1);
944 launch_client_process(client_2);
945}860}
946861
=== modified file 'tests/unit-tests/client/input/test_android_input_receiver.cpp'
--- tests/unit-tests/client/input/test_android_input_receiver.cpp 2013-05-31 16:06:07 +0000
+++ tests/unit-tests/client/input/test_android_input_receiver.cpp 2013-11-07 00:22:14 +0000
@@ -17,8 +17,10 @@
17 */17 */
1818
19#include "src/shared/input/android/android_input_receiver.h"19#include "src/shared/input/android/android_input_receiver.h"
20#include "mir/input/null_input_receiver_report.h"
20#include "mir_toolkit/event.h"21#include "mir_toolkit/event.h"
2122
23
22#include <androidfw/InputTransport.h>24#include <androidfw/InputTransport.h>
2325
24#include <gmock/gmock.h>26#include <gmock/gmock.h>
@@ -27,7 +29,8 @@
27#include <unistd.h>29#include <unistd.h>
28#include <memory>30#include <memory>
2931
30namespace mircva = mir::input::receiver::android;32namespace mircv = mir::input::receiver;
33namespace mircva = mircv::android;
3134
32namespace droidinput = android;35namespace droidinput = android;
3336
@@ -142,14 +145,14 @@
142145
143TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd)146TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd)
144{147{
145 mircva::InputReceiver receiver(client_fd);148 mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
146 149
147 EXPECT_EQ(client_fd, receiver.fd());150 EXPECT_EQ(client_fd, receiver.fd());
148}151}
149152
150TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events)153TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events)
151{154{
152 mircva::InputReceiver receiver(client_fd);155 mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
153 TestingInputProducer producer(server_fd);156 TestingInputProducer producer(server_fd);
154 157
155 producer.produce_a_key_event();158 producer.produce_a_key_event();
@@ -165,7 +168,7 @@
165168
166TEST_F(AndroidInputReceiverSetup, receiver_handles_events)169TEST_F(AndroidInputReceiverSetup, receiver_handles_events)
167{170{
168 mircva::InputReceiver receiver(client_fd);171 mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
169 TestingInputProducer producer(server_fd);172 TestingInputProducer producer(server_fd);
170 173
171 producer.produce_a_key_event();174 producer.produce_a_key_event();
@@ -181,7 +184,7 @@
181184
182TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events)185TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events)
183{186{
184 mircva::InputReceiver receiver(client_fd);187 mircva::InputReceiver receiver(client_fd, std::make_shared<mircv::NullInputReceiverReport>());
185 TestingInputProducer producer(server_fd);188 TestingInputProducer producer(server_fd);
186 189
187 // Produce 3 motion events before client handles any.190 // Produce 3 motion events before client handles any.
188191
=== modified file 'tests/unit-tests/client/input/test_android_input_receiver_thread.cpp'
--- tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2013-05-13 23:20:52 +0000
+++ tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2013-11-07 00:22:14 +0000
@@ -19,6 +19,8 @@
19#include "src/shared/input/android/android_input_receiver_thread.h"19#include "src/shared/input/android/android_input_receiver_thread.h"
20#include "src/shared/input/android/android_input_receiver.h"20#include "src/shared/input/android/android_input_receiver.h"
2121
22#include "mir/input/null_input_receiver_report.h"
23
22#include "mir_toolkit/mir_client_library.h"24#include "mir_toolkit/mir_client_library.h"
2325
24#include <gtest/gtest.h>26#include <gtest/gtest.h>
@@ -30,7 +32,8 @@
3032
31#include <fcntl.h>33#include <fcntl.h>
3234
33namespace mircva = mir::input::receiver::android;35namespace mircv = mir::input::receiver;
36namespace mircva = mircv::android;
3437
35namespace38namespace
36{39{
@@ -43,7 +46,7 @@
43struct MockInputReceiver : public mircva::InputReceiver46struct MockInputReceiver : public mircva::InputReceiver
44{47{
45 MockInputReceiver(int fd)48 MockInputReceiver(int fd)
46 : InputReceiver(fd)49 : InputReceiver(fd, std::make_shared<mircv::NullInputReceiverReport>())
47 {50 {
48 }51 }
49 MOCK_METHOD1(next_event, bool(MirEvent &));52 MOCK_METHOD1(next_event, bool(MirEvent &));

Subscribers

People subscribed via source and target branches