Merge lp:~robertcarr/mir/receive-input-in-client into lp:~mir-team/mir/trunk

Proposed by Robert Carr on 2013-03-25
Status: Merged
Approved by: Thomas Voß on 2013-04-04
Approved revision: 639
Merged at revision: 562
Proposed branch: lp:~robertcarr/mir/receive-input-in-client
Merge into: lp:~mir-team/mir/trunk
Diff against target: 3169 lines (+1583/-233) 69 files modified
To merge this branch: bzr merge lp:~robertcarr/mir/receive-input-in-client
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2013-04-04
Alan Griffiths Approve on 2013-04-04
Chris Halse Rogers 2013-03-25 Approve on 2013-04-04
Review via email: mp+155368@code.launchpad.net

Commit Message

Enable end-to-end keyboard input and test through tests/acceptance-tests/test_client_input.cpp

Description of the Change

This branch contains the client side of input and the finishing touches required to make keyboard input delivery work end to end!

The driving acceptance test is shown in tests/acceptance-tests/test_client_input.cpp

See test_client_mir_surface.cpp for explanation of how client input thread is started and utilized. (this test has an incidental bug! in failing to set fd_items). Implementation revolves around MirSurface::created.

The input machinery on the client side is mclia::InputReceiver and mclia::InputReceiverThread (tests/unit-tests/client/input/...). (some of you may recognize android_input_receiver.cpp from November ;))

Some changes to protobuf_message_processor.cpp were required

Currently this is failing to work with MIR_INPUT_USE_ANDROID_TYPES=false (as is the default). The acceptance test can be observed to fail (the client will only receive one event). This is due to the server failing to receive handling responses from the client and believing the client has gone nonresponsive. The failing code path is around InputDispatcher.cpp:3132, handleReceiveCallback is never invoked.

On the other hand with MIR_INPUT_USE_ANDROID_TYPES=true, handleReceiveCallback is invoked. With this working, the acceptance test passes. You can observe input working in manual testing too! eglapp.c is modified to respond to "q" to quit. I have a messy branch of Qtubuntu (will cleanup) which enables key input as well, and have succesfully run and navigated the qt5/examples/qtdeclarative/quick/keynavigation example!

Some notes from my own look at the diff

* Should the event handler type take MirSurface as the first argument? So far this hasn't been useful. If so, perhaps the EventDelegate should be passed to the Connection, it could be for other kinds of callbacks (such as?...application focus maybe?) as well. ubuntu_platform_api uses no Surface as the first argument and delegate attached to surface (or rather two argument callback, context). Maybe we should just work this way? Seems a shame to not use a delegate struct though as we will just be continually adding arguments (focus_changed_cb, proximity_cb (strawman ;)) etc...)

* The continual writing of std::function<void(MirEvent*)> is unpleasant maybe it should be typedeffed somewhere?

To post a comment you must log in.
Robert Carr (robertcarr) wrote :

Jenkins will fail due to MIR_INPUT_USE_ANDROID_TYPES=false

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Robert Carr (robertcarr) wrote :

Trunk merged. There were some tricky bits around test_client_mir_surface.cpp as trunk was missing:

        server_package.fd_items = num_fd;
and so the test appeared to pass when really it should have failed.

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Chris Halse Rogers (raof) wrote :

In general: at least a little bit of Doxygen comments for the classes you add, please! ☺

------------------------

716 + droidinput::status_t status;
717 + if((status = input_consumer->consume(&event_factory, consume_batches,
718 + default_frame_time, &event_sequence_id, &android_event)) != droidinput::WOULD_BLOCK)

Status is set but never used.

------------------------

807 + int get_fd() const;

I think we'd generally expect this to be called just ‘fd()’?

------------------------

822 + static const bool consume_batches = true;
823 + static const bool do_not_consume_batches = false;
...
825 + static const bool handle_event = true;
826 + static const bool do_not_handle_event = false;

As far as I'm aware we've not been using this pattern elsewhere in the code? I'm not particularly against it, though.

-------------------------

739 + auto status = ::poll(&pfd, 1, timeout.count());
740 +
741 + if (status > 0)
742 + return true;
743 + if (status == 0)
744 + return false;
745 +
746 + // TODO: What to do in case of error? ~racarr
747 + return false;
748 +}

This should probably try polling(!) again while status == EINTR.

Other errors should probably be runtime exceptions; none of the other errors poll can return (EFAULT, EINVAL, ENOMEM) are going to go away without explicit action.

I'm not comfortable letting this in while we're polling every 10msec for input.

review: Needs Fixing
Robert Carr (robertcarr) wrote :

>>> In general: at least a little bit of Doxygen comments for the classes you add, please! ☺

I tried to add some helpful comments!

>> 716 + droidinput::status_t status;
>> 717 + if((status = input_consumer->consume(&event_factory, consume_batches,
>> 718 + default_frame_time, &event_sequence_id, &android_event)) != droidinput::WOULD_BLOCK)

>> Status is set but never used.

Fixed

>> 807 + int get_fd() const;

Fixed

------------------------

>> 822 + static const bool consume_batches = true;
>> 823 + static const bool do_not_consume_batches = false;
...
>> 825 + static const bool handle_event = true;
>> 826 + static const bool do_not_handle_event = false;

>> As far as I'm aware we've not been using this pattern elsewhere in the code? I'm not particularly against >> it, though.

These come from a long series of reviews on an original version of AndroidInputReceiver back in november...I do not have strong opinions though I do think they make the implementation read in a rather literate style.

-------------------------

>> I'm not comfortable letting this in while we're polling every 10msec for input.

The custom poll implementation is replaced with a droidinput::Looper, this way the poll is indefinite, but may still be woken by a wake pipe from another thread.

Robert Carr (robertcarr) wrote :

l725 is a mystery to me. It's easy to observe: Moving it to the constructor causes the acceptance test to fail intermittently.

Robert Carr (robertcarr) wrote :

I'd like to add an exception here:
+ else if (result == ALOOPER_POLL_ERROR) // TODO: Exception?

It's difficult though without a mockable looper to test this exception so I would suggest we target it for a follow-up mp

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Alan Griffiths (alan-griffiths) wrote :

Why is "MirEventDelegate const *event_handler" a separate parameter and not a member of MirSurfaceParameters?

~~~~

563 + virtual ~TestingClientConfiguration() {};

Is this necessary? And shouldn't it be "virtual ~TestingClientConfiguration() = default;"

~~~~

550 +#include <gmock/gmock.h>

There are worse things wrong with this file:

  o WaitCondition doesn't belong in namespace mir
  o anonymous namespaces make things unique to each translation units, and should rarely appear in headers.

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Alan Griffiths (alan-griffiths) wrote :

> >> 822 + static const bool consume_batches = true;
> >> 823 + static const bool do_not_consume_batches = false;
> ...
> >> 825 + static const bool handle_event = true;
> >> 826 + static const bool do_not_handle_event = false;
>
> >> As far as I'm aware we've not been using this pattern elsewhere in the
> code? I'm not particularly against >> it, though.
>
> These come from a long series of reviews on an original version of
> AndroidInputReceiver back in november...I do not have strong opinions though I
> do think they make the implementation read in a rather literate style.

Where are we using it here? I find no use of "do_not_handle_event" in the MP.

It is better to use "enum class BatchMode { do_not_consume_batches, consume_batches };" - which allows type checking on parameters.

review: Needs Fixing
Robert Carr (robertcarr) wrote :

* General cleanup and fix valgrind complaints r606-610
* Android input application handle should take a weak reference to prevent circular ownership. (r608)
* Remove strange constants
* Cleanup wait_condition.h

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Alan Griffiths (alan-griffiths) wrote :

321 InputMessage msg;
322 + memset(&msg, 0, sizeof(InputMessage));
...
330 InputMessage msg;
331 + memset(&msg, 0, sizeof(InputMessage));
...
339 InputMessage msg;
340 + memset(&msg, 0, sizeof(InputMessage));

Wouldn't a default constructor be less repetitive?

~~~~

Why is "MirEventDelegate const *event_handler" a separate parameter and not a member of MirSurfaceParameters?

~~~~

"Should the event handler type take MirSurface as the first argument? ... ubuntu_platform_api uses no Surface as the first argument and delegate attached to surface (or rather two argument callback, context). Maybe we should just work this way?"

review: Needs Information
Robert Carr (robertcarr) wrote :

>> 321 InputMessage msg;
>> 322 + memset(&msg, 0, sizeof(InputMessage));
>> ...
>> 330 InputMessage msg;
>> 331 + memset(&msg, 0, sizeof(InputMessage));
>> ...
>> 339 InputMessage msg;
>> 340 + memset(&msg, 0, sizeof(InputMessage));

Yes it would says r618.

>> Why is "MirEventDelegate const *event_handler" a separate parameter and not a member of
>> MirSurfaceParameters?

I think it's a very different kind of parameter (not sent over the wire to the server, not used for construction, not serializable). Maybe the API user doesn't care?

>> "Should the event handler type take MirSurface as the first argument? ... ubuntu_platform_api uses no
>> Surface as the first argument and delegate attached to surface (or rather two argument callback, context). >> Maybe we should just work this way?"

This was just kind of a thought I threw out. I like the current signature (surface, ev, ctx) and it is in keeping with C style used in GLib, etc...

Alan Griffiths (alan-griffiths) wrote :

Spurious whitespace:

1302 -
1303 +

review: Needs Fixing
Alan Griffiths (alan-griffiths) wrote :

Probably OK once the conflict is fixed

review: Abstain
Alan Griffiths (alan-griffiths) wrote :

1236 -
1237 +

Spurious whitespace

Alan Griffiths (alan-griffiths) wrote :

2667 - auto surface = std::make_shared<MirSurface> (connection.get(),
2668 - *client_comm_channel,
2669 - logger,
2670 - mock_buffer_factory,
2671 - params,
2672 - &empty_callback,
2673 - nullptr);
2674 + auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, (void*) NULL);

Using "(void*) NULL" in place of "nullptr" isn't an improvement.

review: Needs Fixing
Alan Griffiths (alan-griffiths) wrote :

333 +

Spurious whitespace

There's also some NULL usage.

But I'll abstain as there's nothing obvious to block on and I'm at EOD.

review: Abstain
Robert Carr (robertcarr) wrote :

Many whitespace and style fixes

Chris Halse Rogers (raof) wrote :

So, we can probably land this, and do some followup cleaning:

155 + surface = mir_surface_create_sync(connection, &request_params, NULL);

Might as well use nullptr here (and change the surrounding NULL checks).

src/client/input/android_input_platform.{cpp,h} is GPlv3+; should be LGPLv3+
src/client/input/android_input_receiver.{cpp,h} is GPlv3+; should be LGPLv3+
src/client/input/android_input_receiver_thread.{cpp,h} is GPlv3+; should be LGPLv3+
src/client/input/input_platform.h is GPlv3+; should be LGPLv3+
…and basically all the added files, it seems.

A bunch of cases of ~Foo() {}, which I think would more idiomatically be ~Foo() = default;

1356 + ("enable-input,i", po::value<bool>(), "Enable input. [bool:default=false]")
1357 (log_display, po::value<bool>(), "Log the Display report. [bool:default=false]")
1358 (log_app_mediator, po::value<bool>(), "Log the ApplicationMediator report. [bool:default=false]")
1359 (log_msg_processor, po::value<bool>(), "log the MessageProcessor report")
1360 @@ -316,9 +318,12 @@
1361 mir::DefaultServerConfiguration::the_input_manager()
1362 {
1363 return input_manager(
1364 - [&, this]()
1365 + [&, this]() -> std::shared_ptr<mi::InputManager>
1366 {
1367 - return mi::create_input_manager(the_event_filters(), the_display());
1368 + if (the_options()->get("enable-input", false))
1369 + return mi::create_input_manager(the_event_filters(), the_display());
1370 + else
1371 + return std::make_shared<mi::NullInputManager>();

Is this the right way around? It looks like input is turned off if ‘enable-input’ is true?

2641 +// thread->join();

Looks like you've got some temporary testing code still hanging around?

2883 - auto surface = std::make_shared<MirSurface> (connection.get(),
2884 - *client_comm_channel,
2885 - logger,
2886 - mock_buffer_factory,
2887 - params,
2888 - &empty_callback,
2889 - nullptr);
2890 + auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
(and further examples in that file)
I think we prefer the former formatting, with shorter lines?

review: Approve
Alan Griffiths (alan-griffiths) wrote :

> 1368 + if (the_options()->get("enable-input", false))
> 1369 + return mi::create_input_manager(the_event_filters(),
> the_display());
> 1370 + else
> 1371 + return std::make_shared<mi::NullInputManager>();
>
> Is this the right way around? It looks like input is turned off if ‘enable-
> input’ is true?

It is the right way "false" is the default value for get. Maybe we should add a helper function so that we can write "the_options()->get("enable-input", default_to(false))"?

Alan Griffiths (alan-griffiths) wrote :

>So, we can probably land this, and do some followup cleaning:

+1

...
> src/client/input/android_input_platform.{cpp,h} is GPlv3+; should be LGPLv3+
> src/client/input/android_input_receiver.{cpp,h} is GPlv3+; should be LGPLv3+
> src/client/input/android_input_receiver_thread.{cpp,h} is GPlv3+; should be
> LGPLv3+
> src/client/input/input_platform.h is GPlv3+; should be LGPLv3+
> …and basically all the added files, it seems.
>
> A bunch of cases of ~Foo() {}, which I think would more idiomatically be
> ~Foo() = default;

We can probably fix this when we clean up a whole bunch of potentially throwing destructors.

> 2641 +// thread->join();
>
> Looks like you've got some temporary testing code still hanging around?
>
> 2883 - auto surface = std::make_shared<MirSurface> (connection.get(),
> 2884 -
> *client_comm_channel,
> 2885 - logger,
> 2886 - mock_buffer_factory,
> 2887 - params,
> 2888 - &empty_callback,
> 2889 - nullptr);
> 2890 + auto surface = std::make_shared<MirSurface> (connection.get(),
> *client_comm_channel, logger, mock_buffer_factory, input_platform, params,
> nullptr, &empty_callback, nullptr);
> (and further examples in that file)
> I think we prefer the former formatting, with shorter lines?

I think we should prefer a third style - breaking before the first parameter when necessary. (The original is fragile when renaming anything that appears before that point - and we do global renames often enough for it to matter.)

review: Approve
review: Approve (continuous-integration)

Preview Diff

1=== modified file '3rd_party/CMakeLists.txt'
2--- 3rd_party/CMakeLists.txt 2013-03-21 03:32:59 +0000
3+++ 3rd_party/CMakeLists.txt 2013-04-03 18:49:21 +0000
4@@ -28,10 +28,8 @@
5 add_subdirectory(android-fbtype)
6 endif()
7
8-if (NOT MIR_DISABLE_INPUT)
9- include_directories(${CMAKE_CURRENT_SOURCE_DIR}/android-deps)
10- add_subdirectory(android-input)
11-endif()
12+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/android-deps)
13+add_subdirectory(android-input)
14
15 set(MIR_ANDROID_INCLUDE_DIRECTORIES ${MIR_ANDROID_INCLUDE_DIRECTORIES} PARENT_SCOPE)
16 set(
17@@ -39,9 +37,7 @@
18 ${MIR_ANDROID_INPUT_COMPILE_FLAGS}
19 PARENT_SCOPE)
20
21-if (NOT MIR_DISABLE_INPUT)
22 target_link_libraries(
23 3rd_party
24
25 android-input)
26-endif()
27
28=== modified file '3rd_party/android-deps/std/SortedVector.h'
29--- 3rd_party/android-deps/std/SortedVector.h 2013-03-13 04:54:15 +0000
30+++ 3rd_party/android-deps/std/SortedVector.h 2013-04-03 18:49:21 +0000
31@@ -133,7 +133,7 @@
32 ssize_t remove(const ValueType& item)
33 {
34 auto remove_pos = lower_bound(begin(), end(), item);
35- if (*remove_pos == item)
36+ if (remove_pos != end() && *remove_pos == item)
37 {
38 auto removed_at = erase(remove_pos);
39 return distance(begin(), removed_at);
40
41=== modified file '3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h'
42--- 3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h 2013-03-13 04:54:15 +0000
43+++ 3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h 2013-04-03 18:49:21 +0000
44@@ -43,6 +43,8 @@
45 * Intermediate representation used to send input events and related signals.
46 */
47 struct InputMessage {
48+ InputMessage();
49+
50 enum {
51 TYPE_KEY = 1,
52 TYPE_MOTION = 2,
53
54=== modified file '3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp'
55--- 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp 2013-02-11 11:51:22 +0000
56+++ 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp 2013-04-03 18:49:21 +0000
57@@ -63,6 +63,11 @@
58
59 // --- InputMessage ---
60
61+InputMessage::InputMessage()
62+{
63+ memset(this, 0, sizeof(InputMessage));
64+}
65+
66 bool InputMessage::isValid(size_t actualSize) const {
67 if (size() == actualSize) {
68 switch (header.type) {
69
70=== modified file 'CMakeLists.txt'
71--- CMakeLists.txt 2013-03-28 14:20:06 +0000
72+++ CMakeLists.txt 2013-04-03 18:49:21 +0000
73@@ -103,13 +103,6 @@
74 "graphics backend to build (options are 'gbm' or 'android')"
75 )
76
77-set (MIR_DISABLE_INPUT
78- false
79- CACHE
80- BOOL
81- "Don't build the input subsystem"
82-)
83-
84 set (MIR_INPUT_USE_ANDROID_TYPES
85 false
86 CACHE
87
88=== modified file 'cross-compile-chroot.sh'
89--- cross-compile-chroot.sh 2013-03-26 15:55:51 +0000
90+++ cross-compile-chroot.sh 2013-04-03 18:49:21 +0000
91@@ -26,7 +26,6 @@
92 -DBoost_COMPILER=-gcc \
93 -DMIR_ENABLE_DEATH_TESTS=NO \
94 -DMIR_PLATFORM=android \
95- -DMIR_DISABLE_INPUT=true \
96 ..
97
98 cmake --build .
99
100=== modified file 'debian/rules'
101--- debian/rules 2013-03-13 04:54:15 +0000
102+++ debian/rules 2013-04-03 18:49:21 +0000
103@@ -15,7 +15,6 @@
104
105 COMMON_CONFIGURE_OPTIONS = \
106 -DMIR_DISABLE_EPOLL_REACTOR=YES \
107- -DMIR_DISABLE_INPUT=YES \
108 -DBUILD_DOXYGEN=YES
109
110 # We need to rely on the select-based reactor to fix the ppa builds.
111
112=== modified file 'doc/building_source_for_android.md'
113--- doc/building_source_for_android.md 2013-03-26 16:30:53 +0000
114+++ doc/building_source_for_android.md 2013-04-03 18:49:21 +0000
115@@ -42,7 +42,7 @@
116
117 $ bzr branch lp:mir
118 $ mkdir mir/build; cd mir/build
119- $ cmake -DBoost_COMPILER=-gcc -DMIR_ENABLE_DEATH_TESTS=NO -DMIR_PLATFORM=android -DMIR_DISABLE_INPUT=yes ..
120+ $ cmake -DBoost_COMPILER=-gcc -DMIR_ENABLE_DEATH_TESTS=NO -DMIR_PLATFORM=android ..
121
122 Cross Compile
123 -------------
124@@ -63,7 +63,7 @@
125
126 $ bzr branch lp:mir
127 $ mkdir mir/build; cd mir/build
128- $ MIR_NDK_PATH=/path/to/depenendcies/chroot cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake -DBoost_COMPILER=-gcc -DMIR_ENABLE_DEATH_TESTS=NO -DMIR_PLATFORM=android -DMIR_DISABLE_INPUT=yes ..
129+ $ MIR_NDK_PATH=/path/to/depenendcies/chroot cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake -DBoost_COMPILER=-gcc -DMIR_ENABLE_DEATH_TESTS=NO -DMIR_PLATFORM=android ..
130 $ make
131
132 N.B. The `cross-compile-android.sh` script in mir's top level directory
133
134=== modified file 'examples/demo_client.c'
135--- examples/demo_client.c 2013-03-22 10:34:16 +0000
136+++ examples/demo_client.c 2013-04-03 18:49:21 +0000
137@@ -129,7 +129,7 @@
138 /// \snippet demo_client.c surface_create_tag
139 ///\internal [surface_create_tag]
140 // ...we create a surface using that format and wait for callback to complete.
141- mir_wait_for(mir_surface_create(mcd.connection, &request_params, surface_create_callback, &mcd));
142+ mir_wait_for(mir_surface_create(mcd.connection, &request_params, NULL, surface_create_callback, &mcd));
143 puts("Surface created");
144 ///\internal [surface_create_tag]
145
146
147=== modified file 'examples/demo_client_accelerated.cpp'
148--- examples/demo_client_accelerated.cpp 2013-03-22 10:34:16 +0000
149+++ examples/demo_client_accelerated.cpp 2013-04-03 18:49:21 +0000
150@@ -72,7 +72,7 @@
151 MirSurfaceParameters const request_params =
152 {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_hardware};
153
154- surface = mir_surface_create_sync(connection, &request_params);
155+ surface = mir_surface_create_sync(connection, &request_params, NULL);
156 assert(surface != NULL);
157 assert(mir_surface_is_valid(surface));
158 assert(strcmp(mir_surface_get_error_message(surface), "") == 0);
159
160=== modified file 'examples/demo_client_unaccelerated.c'
161--- examples/demo_client_unaccelerated.c 2013-03-29 16:51:35 +0000
162+++ examples/demo_client_unaccelerated.c 2013-04-03 18:49:21 +0000
163@@ -132,7 +132,7 @@
164 MirSurfaceParameters const request_params =
165 {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_software};
166
167- surface = mir_surface_create_sync(connection, &request_params);
168+ surface = mir_surface_create_sync(connection, &request_params, NULL);
169 assert(surface != NULL);
170 assert(mir_surface_is_valid(surface));
171 assert(strcmp(mir_surface_get_error_message(surface), "") == 0);
172
173=== modified file 'examples/eglapp.c'
174--- examples/eglapp.c 2013-03-20 05:03:03 +0000
175+++ examples/eglapp.c 2013-04-03 18:49:21 +0000
176@@ -85,6 +85,14 @@
177 }
178 }
179
180+static void mir_eglapp_handle_input(MirSurface* surface, MirEvent* ev, void* context)
181+{
182+ (void) surface;
183+ (void) context;
184+ if (ev->details.key.key_code == 45) /* Q */
185+ running = 0;
186+}
187+
188 mir_eglapp_bool mir_eglapp_init(int *width, int *height)
189 {
190 EGLint attribs[] =
191@@ -106,6 +114,11 @@
192 mir_pixel_format_xbgr_8888,
193 mir_buffer_usage_hardware
194 };
195+ MirEventDelegate delegate =
196+ {
197+ mir_eglapp_handle_input,
198+ NULL
199+ };
200 MirDisplayInfo dinfo;
201 MirSurface *surface;
202 EGLConfig eglconfig;
203@@ -127,7 +140,7 @@
204 surfaceparm.pixel_format = dinfo.supported_pixel_format[0];
205 printf("Using pixel format #%d\n", surfaceparm.pixel_format);
206
207- surface = mir_surface_create_sync(connection, &surfaceparm);
208+ surface = mir_surface_create_sync(connection, &surfaceparm, &delegate);
209 CHECK(mir_surface_is_valid(surface), "Can't create a surface");
210
211 egldisplay = eglGetDisplay(
212
213=== modified file 'examples/render_surfaces.cpp'
214--- examples/render_surfaces.cpp 2013-04-02 09:36:09 +0000
215+++ examples/render_surfaces.cpp 2013-04-03 18:49:21 +0000
216@@ -23,7 +23,7 @@
217 #include "mir/geometry/size.h"
218 #include "mir/graphics/buffer_initializer.h"
219 #include "mir/graphics/display.h"
220-#include "mir/input/input_manager.h"
221+#include "mir/input/null_input_manager.h"
222 #include "mir/shell/surface_builder.h"
223 #include "mir/surfaces/surface.h"
224 #include "mir/default_server_configuration.h"
225@@ -380,20 +380,6 @@
226 // Stub out input.
227 std::shared_ptr<mi::InputManager> RenderSurfacesServerConfiguration::the_input_manager()
228 {
229- struct NullInputManager : public mi::InputManager
230- {
231- void start() {}
232- void stop() {}
233- std::shared_ptr<mi::InputChannel> make_input_channel()
234- {
235- return std::shared_ptr<mi::InputChannel>();
236- }
237- void set_input_focus_to(std::shared_ptr<mi::SessionTarget> const& /* session */,
238- std::shared_ptr<mi::SurfaceTarget> const& /* surface */)
239- {
240- }
241- };
242-
243- return std::make_shared<NullInputManager>();
244+ return std::make_shared<mi::NullInputManager>();
245 }
246 ///\internal [NullInputManager_tag]
247
248=== modified file 'include/client/mir_toolkit/mir_client_library.h'
249--- include/client/mir_toolkit/mir_client_library.h 2013-03-29 11:39:30 +0000
250+++ include/client/mir_toolkit/mir_client_library.h 2013-04-03 18:49:21 +0000
251@@ -124,6 +124,7 @@
252 MirWaitHandle *mir_surface_create(
253 MirConnection *connection,
254 MirSurfaceParameters const *surface_parameters,
255+ MirEventDelegate const *event_handler,
256 mir_surface_lifecycle_callback callback,
257 void *context);
258
259@@ -135,7 +136,8 @@
260 * \return The resulting surface
261 */
262 MirSurface *mir_surface_create_sync(MirConnection *connection,
263- MirSurfaceParameters const *params);
264+ MirSurfaceParameters const *params,
265+ MirEventDelegate const *event_handler);
266
267 /**
268 * Get a window type that can be used for OpenGL ES 2.0 acceleration.
269
270=== added file 'include/server/mir/input/null_input_manager.h'
271--- include/server/mir/input/null_input_manager.h 1970-01-01 00:00:00 +0000
272+++ include/server/mir/input/null_input_manager.h 2013-04-03 18:49:21 +0000
273@@ -0,0 +1,56 @@
274+/*
275+ * Copyright © 2013 Canonical Ltd.
276+ *
277+ * This program is free software: you can redistribute it and/or modify it
278+ * under the terms of the GNU Lesser General Public License version 3,
279+ * as published by the Free Software Foundation.
280+ *
281+ * This program is distributed in the hope that it will be useful,
282+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
283+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
284+ * GNU General Public License for more details.
285+ *
286+ * You should have received a copy of the GNU Lesser General Public License
287+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
288+ *
289+ * Authored by: Robert Carr <robert.carr@canonical.com>
290+ */
291+
292+#ifndef MIR_INPUT_NULL_INPUT_MANAGER_H_
293+#define MIR_INPUT_NULL_INPUT_MANAGER_H_
294+
295+#include "mir/input/input_manager.h"
296+
297+namespace mir
298+{
299+namespace input
300+{
301+
302+class NullInputManager : public InputManager
303+{
304+public:
305+ NullInputManager() {};
306+ virtual ~NullInputManager() {}
307+
308+ void start() {}
309+ void stop() {}
310+
311+ std::shared_ptr<InputChannel> make_input_channel()
312+ {
313+ return std::shared_ptr<InputChannel>();
314+ }
315+
316+ virtual void set_input_focus_to(std::shared_ptr<input::SessionTarget> const& /* session */,
317+ std::shared_ptr<input::SurfaceTarget> const& /* surface */)
318+ {
319+ }
320+
321+protected:
322+ NullInputManager(const NullInputManager&) = delete;
323+ NullInputManager& operator=(const NullInputManager&) = delete;
324+};
325+
326+}
327+}
328+
329+#endif // MIR_INPUT_NULL_INPUT_MANAGER
330
331=== added directory 'include/shared/mir/input'
332=== added directory 'include/shared/mir/input/android'
333=== renamed file 'src/server/input/android/android_input_lexicon.h' => 'include/shared/mir/input/android/android_input_lexicon.h'
334--- src/server/input/android/android_input_lexicon.h 2013-03-13 04:54:15 +0000
335+++ include/shared/mir/input/android/android_input_lexicon.h 2013-04-03 18:49:21 +0000
336@@ -35,11 +35,18 @@
337 {
338 namespace android
339 {
340+namespace transport
341+{
342+
343+/// The Lexicon translates droidinput event types to MirEvent types prior to
344+/// shell or client handling.
345 class Lexicon
346 {
347 public:
348 static void translate(const droidinput::InputEvent *android_event, MirEvent &mir_event);
349 };
350+
351+}
352 }
353 }
354 }
355
356=== modified file 'include/shared/mir_toolkit/c_types.h'
357--- include/shared/mir_toolkit/c_types.h 2013-03-29 11:27:00 +0000
358+++ include/shared/mir_toolkit/c_types.h 2013-04-03 18:49:21 +0000
359@@ -19,6 +19,8 @@
360 #ifndef MIR_TOOLKIT_C_TYPES_H_
361 #define MIR_TOOLKIT_C_TYPES_H_
362
363+#include <mir_toolkit/input/event.h>
364+
365 #ifdef __cplusplus
366 /**
367 * \defgroup mir_toolkit MIR graphics tools API
368@@ -60,6 +62,15 @@
369 typedef void (*mir_surface_lifecycle_callback)(MirSurface *surface, void *client_context);
370
371 /**
372+ * Callback member of MirEventDelegate for handling of input events.
373+ * \param [in] surface The surface on which an event has occurred
374+ * \param [in] event The event to be handled
375+ * \param [in,out] context The context provided by client during delegate
376+ * registration.
377+ */
378+typedef void (*mir_event_delegate_handle_input_callback)(MirSurface* surface, MirEvent* ev, void* context);
379+
380+/**
381 * The order of components in a format enum matches the
382 * order of the components as they would be written in an
383 * integer representing a pixel value of that format.
384@@ -158,6 +169,16 @@
385 MirPixelFormat supported_pixel_format[mir_supported_pixel_format_max];
386 } MirDisplayInfo;
387
388+/**
389+ * MirEventDelegate may be used to specify (at surface creation time) callbacks for
390+ * handling of input events
391+ */
392+typedef struct MirEventDelegate
393+{
394+ mir_event_delegate_handle_input_callback handle_input;
395+ void *context;
396+} MirEventDelegate;
397+
398 #ifdef __cplusplus
399 }
400 /**@}*/
401
402=== modified file 'include/shared/mir_toolkit/input/event.h'
403--- include/shared/mir_toolkit/input/event.h 2013-03-29 11:39:30 +0000
404+++ include/shared/mir_toolkit/input/event.h 2013-04-03 18:49:21 +0000
405@@ -41,7 +41,7 @@
406 MIR_INPUT_EVENT_TYPE_HW_SWITCH
407 } MirEventType;
408
409- struct MirEvent
410+ typedef struct MirEvent
411 {
412 /* Generic event properties */
413 MirEventType type;
414@@ -94,7 +94,7 @@
415 } pointer_coordinates[MIR_INPUT_EVENT_MAX_POINTER_COUNT];
416 } motion;
417 } details;
418- };
419+ } MirEvent;
420
421 #ifdef __cplusplus
422 }
423
424=== modified file 'include/test/mir_test/wait_condition.h'
425--- include/test/mir_test/wait_condition.h 2013-03-22 16:41:59 +0000
426+++ include/test/mir_test/wait_condition.h 2013-04-03 18:49:21 +0000
427@@ -19,12 +19,16 @@
428 #ifndef MIR_TEST_WAIT_CONDITION_H_
429 #define MIR_TEST_WAIT_CONDITION_H_
430
431+#include <gmock/gmock.h>
432+
433 #include <chrono>
434 #include <mutex>
435 #include <condition_variable>
436
437 namespace mir
438 {
439+namespace test
440+{
441 struct WaitCondition
442 {
443 WaitCondition() : woken(false) {}
444@@ -46,10 +50,7 @@
445 std::condition_variable condition;
446 bool woken;
447 };
448-}
449
450-namespace
451-{
452 ACTION_P(ReturnFalseAndWakeUp, wait_condition)
453 {
454 wait_condition->wake_up_everyone();
455@@ -60,5 +61,6 @@
456 wait_condition->wake_up_everyone();
457 }
458 }
459+}
460
461 #endif // MIR_TEST_WAIT_CONDITION_H_
462
463=== modified file 'src/client/CMakeLists.txt'
464--- src/client/CMakeLists.txt 2013-03-29 22:30:35 +0000
465+++ src/client/CMakeLists.txt 2013-04-03 18:49:21 +0000
466@@ -35,6 +35,7 @@
467 mir_basic_rpc_channel.cpp
468 ${PROTO_SRCS}
469 )
470+add_subdirectory(input)
471
472 list(APPEND CLIENT_SOURCES
473 mir_socket_rpc_channel.cpp
474@@ -82,15 +83,15 @@
475 SOVERSION ${MIR_VERSION_MAJOR}
476 )
477
478-target_link_libraries(
479- mirclient
480-
481+set(
482+ MIR_CLIENT_LIBRARIES
483 ${Boost_LIBRARIES}
484 ${CMAKE_THREAD_LIBS_INIT}
485 ${LIBHARDWARE_LIBRARIES}
486 ${PROTOBUF_LIBRARIES}
487
488 mirprotobuf
489+ mirinputandroidtransport
490
491 ${DRM_LIBRARIES}
492 ${MIR_COMMON_PLATFORM_LIBRARIES}
493@@ -98,6 +99,12 @@
494 3rd_party
495 )
496
497+target_link_libraries(
498+ mirclient
499+
500+ ${MIR_CLIENT_LIBRARIES}
501+)
502+
503 install(
504 TARGETS mirclient
505 LIBRARY DESTINATION lib
506
507=== added directory 'src/client/input'
508=== added file 'src/client/input/CMakeLists.txt'
509--- src/client/input/CMakeLists.txt 1970-01-01 00:00:00 +0000
510+++ src/client/input/CMakeLists.txt 2013-04-03 18:49:21 +0000
511@@ -0,0 +1,12 @@
512+list(
513+ APPEND CLIENT_SOURCES
514+ ${CMAKE_CURRENT_SOURCE_DIR}/android_input_receiver.cpp
515+ ${CMAKE_CURRENT_SOURCE_DIR}/android_input_receiver_thread.cpp
516+ ${CMAKE_CURRENT_SOURCE_DIR}/android_input_platform.cpp
517+)
518+
519+set(
520+ CLIENT_SOURCES
521+ ${CLIENT_SOURCES}
522+ PARENT_SCOPE
523+)
524
525=== added file 'src/client/input/android_input_platform.cpp'
526--- src/client/input/android_input_platform.cpp 1970-01-01 00:00:00 +0000
527+++ src/client/input/android_input_platform.cpp 2013-04-03 18:49:21 +0000
528@@ -0,0 +1,44 @@
529+/*
530+ * Copyright © 2013 Canonical Ltd.
531+ *
532+ * This program is free software: you can redistribute it and/or modify
533+ * it under the terms of the GNU General Public License version 3 as
534+ * published by the Free Software Foundation.
535+ *
536+ * This program is distributed in the hope that it will be useful,
537+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
538+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
539+ * GNU General Public License for more details.
540+ *
541+ * You should have received a copy of the GNU General Public License
542+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
543+ *
544+ * Authored by: Robert Carr <robert.carr@canonical.com>
545+ */
546+
547+#include "android_input_platform.h"
548+#include "android_input_receiver.h"
549+#include "android_input_receiver_thread.h"
550+
551+namespace mcli = mir::client::input;
552+namespace mclia = mcli::android;
553+
554+mclia::AndroidInputPlatform::AndroidInputPlatform()
555+{
556+}
557+
558+mclia::AndroidInputPlatform::~AndroidInputPlatform()
559+{
560+}
561+
562+std::shared_ptr<mcli::InputReceiverThread> mclia::AndroidInputPlatform::create_input_thread(
563+ int fd, std::function<void(MirEvent*)> const& callback)
564+{
565+ auto receiver = std::make_shared<mclia::InputReceiver>(fd);
566+ return std::make_shared<mclia::InputReceiverThread>(receiver, callback);
567+}
568+
569+std::shared_ptr<mcli::InputPlatform> mcli::InputPlatform::create()
570+{
571+ return std::make_shared<mclia::AndroidInputPlatform>();
572+}
573
574=== added file 'src/client/input/android_input_platform.h'
575--- src/client/input/android_input_platform.h 1970-01-01 00:00:00 +0000
576+++ src/client/input/android_input_platform.h 2013-04-03 18:49:21 +0000
577@@ -0,0 +1,52 @@
578+/*
579+ * Copyright © 2013 Canonical Ltd.
580+ *
581+ * This program is free software: you can redistribute it and/or modify
582+ * it under the terms of the GNU General Public License version 3 as
583+ * published by the Free Software Foundation.
584+ *
585+ * This program is distributed in the hope that it will be useful,
586+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
587+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
588+ * GNU General Public License for more details.
589+ *
590+ * You should have received a copy of the GNU General Public License
591+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
592+ *
593+ * Authored by: Robert Carr <robert.carr@canonical.com>
594+ */
595+
596+#ifndef MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_
597+#define MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_
598+
599+#include "input_platform.h"
600+
601+namespace mir
602+{
603+namespace client
604+{
605+namespace input
606+{
607+namespace android
608+{
609+
610+/// Implementation of client input machinery for android input stack wire protocol.
611+class AndroidInputPlatform : public InputPlatform
612+{
613+public:
614+ AndroidInputPlatform();
615+ virtual ~AndroidInputPlatform();
616+
617+ std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback);
618+
619+protected:
620+ AndroidInputPlatform(const AndroidInputPlatform&) = delete;
621+ AndroidInputPlatform& operator=(const AndroidInputPlatform&) = delete;
622+};
623+
624+}
625+}
626+}
627+} // namespace mir
628+
629+#endif // MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_
630
631=== added file 'src/client/input/android_input_receiver.cpp'
632--- src/client/input/android_input_receiver.cpp 1970-01-01 00:00:00 +0000
633+++ src/client/input/android_input_receiver.cpp 2013-04-03 18:49:21 +0000
634@@ -0,0 +1,91 @@
635+/*
636+ * Copyright © 2013 Canonical Ltd.
637+ *
638+ * This program is free software: you can redistribute it and/or modify
639+ * it under the terms of the GNU General Public License version 3 as
640+ * published by the Free Software Foundation.
641+ *
642+ * This program is distributed in the hope that it will be useful,
643+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
644+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645+ * GNU General Public License for more details.
646+ *
647+ * You should have received a copy of the GNU General Public License
648+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
649+ *
650+ * Authored by: Robert Carr <robert.carr@canonical.com>
651+ */
652+
653+#include "android_input_receiver.h"
654+#include "mir/input/android/android_input_lexicon.h"
655+
656+#include <androidfw/InputTransport.h>
657+#include <utils/Looper.h>
658+
659+namespace mclia = mir::client::input::android;
660+namespace miat = mir::input::android::transport;
661+
662+mclia::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel)
663+ : input_channel(input_channel),
664+ input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
665+ looper(new droidinput::Looper(true)),
666+ fd_added(false)
667+{
668+}
669+
670+mclia::InputReceiver::InputReceiver(int fd)
671+ : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)),
672+ input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
673+ looper(new droidinput::Looper(true)),
674+ fd_added(false)
675+{
676+}
677+
678+mclia::InputReceiver::~InputReceiver()
679+{
680+}
681+
682+int mclia::InputReceiver::fd() const
683+{
684+ return input_channel->getFd();
685+}
686+
687+// TODO: We use a droidinput::Looper here for polling functionality but it might be nice to integrate
688+// with the existing client io_service ~racarr ~tvoss
689+bool mclia::InputReceiver::next_event(std::chrono::milliseconds const& timeout, MirEvent &ev)
690+{
691+ droidinput::InputEvent *android_event;
692+ uint32_t event_sequence_id;
693+ bool handled_event = false;
694+
695+ if (!fd_added)
696+ {
697+ // TODO: Why will this fail from the constructor? ~racarr
698+ looper->addFd(fd(), fd(), ALOOPER_EVENT_INPUT, nullptr, nullptr);
699+ fd_added = true;
700+ }
701+
702+ auto result = looper->pollOnce(timeout.count());
703+ if (result == ALOOPER_POLL_WAKE)
704+ return false;
705+ else if (result == ALOOPER_POLL_ERROR) // TODO: Exception?
706+ return false;
707+
708+ if(input_consumer->consume(&event_factory, true,
709+ -1, &event_sequence_id, &android_event) != droidinput::WOULD_BLOCK)
710+ {
711+ miat::Lexicon::translate(android_event, ev);
712+ input_consumer->sendFinishedSignal(event_sequence_id, true);
713+ handled_event = true;
714+ }
715+
716+ // So far once we have sent an event to the client there is no chance for redispatch
717+ // so the client handles all events.
718+
719+ return handled_event;
720+}
721+
722+void mclia::InputReceiver::wake()
723+{
724+ looper->wake();
725+}
726
727=== added file 'src/client/input/android_input_receiver.h'
728--- src/client/input/android_input_receiver.h 1970-01-01 00:00:00 +0000
729+++ src/client/input/android_input_receiver.h 2013-04-03 18:49:21 +0000
730@@ -0,0 +1,84 @@
731+/*
732+ * Copyright © 2013 Canonical Ltd.
733+ *
734+ * This program is free software: you can redistribute it and/or modify
735+ * it under the terms of the GNU General Public License version 3 as
736+ * published by the Free Software Foundation.
737+ *
738+ * This program is distributed in the hope that it will be useful,
739+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
740+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
741+ * GNU General Public License for more details.
742+ *
743+ * You should have received a copy of the GNU General Public License
744+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
745+ *
746+ * Authored by: Robert Carr <robert.carr@canonical.com>
747+ */
748+
749+#ifndef MIR_INPUT_ANDROID_INPUT_RECEIVER_H_
750+#define MIR_INPUT_ANDROID_INPUT_RECEIVER_H_
751+
752+#include "mir_toolkit/input/event.h"
753+
754+#include <utils/StrongPointer.h>
755+#include <androidfw/Input.h>
756+
757+#include <memory>
758+#include <chrono>
759+
760+namespace droidinput = android;
761+
762+namespace android
763+{
764+class InputChannel;
765+class InputConsumer;
766+class Looper;
767+}
768+
769+namespace mir
770+{
771+namespace client
772+{
773+namespace input
774+{
775+namespace android
776+{
777+
778+/// Synchronously receives input events in a blocking manner
779+class InputReceiver
780+{
781+public:
782+ InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel);
783+ InputReceiver(int fd);
784+
785+ virtual ~InputReceiver();
786+ int fd() const;
787+
788+ /// Synchronously receive an event with millisecond timeout. A negative timeout value
789+ /// is used to request indefinite polling.
790+ virtual bool next_event(std::chrono::milliseconds const& timeout, MirEvent &ev);
791+ virtual bool next_event(MirEvent &ev) { return next_event(std::chrono::milliseconds(-1), ev); }
792+
793+ /// May be used from any thread to wake an InputReceiver blocked in next_event
794+ virtual void wake();
795+
796+protected:
797+ InputReceiver(const InputReceiver&) = delete;
798+ InputReceiver& operator=(const InputReceiver&) = delete;
799+
800+private:
801+ droidinput::sp<droidinput::InputChannel> input_channel;
802+ std::shared_ptr<droidinput::InputConsumer> input_consumer;
803+ droidinput::PreallocatedInputEventFactory event_factory;
804+ droidinput::sp<droidinput::Looper> looper;
805+
806+ bool fd_added;
807+};
808+
809+}
810+}
811+}
812+} // namespace mir
813+
814+#endif // MIR_INPUT_ANDROID_INPUT_RECEIVER_H_
815
816=== added file 'src/client/input/android_input_receiver_thread.cpp'
817--- src/client/input/android_input_receiver_thread.cpp 1970-01-01 00:00:00 +0000
818+++ src/client/input/android_input_receiver_thread.cpp 2013-04-03 18:49:21 +0000
819@@ -0,0 +1,68 @@
820+/*
821+ * Copyright © 2013 Canonical Ltd.
822+ *
823+ * This program is free software: you can redistribute it and/or modify
824+ * it under the terms of the GNU General Public License version 3 as
825+ * published by the Free Software Foundation.
826+ *
827+ * This program is distributed in the hope that it will be useful,
828+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
829+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
830+ * GNU General Public License for more details.
831+ *
832+ * You should have received a copy of the GNU General Public License
833+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
834+ *
835+ * Authored by: Robert Carr <robert.carr@canonical.com>
836+ */
837+
838+#include "android_input_receiver_thread.h"
839+#include "android_input_receiver.h"
840+
841+#include <thread>
842+
843+namespace mclia = mir::client::input::android;
844+
845+mclia::InputReceiverThread::InputReceiverThread(std::shared_ptr<mclia::InputReceiver> const& receiver,
846+ std::function<void(MirEvent*)> const& event_handling_callback)
847+ : receiver(receiver),
848+ handler(event_handling_callback),
849+ running(false)
850+{
851+}
852+
853+mclia::InputReceiverThread::~InputReceiverThread()
854+{
855+ if (running)
856+ stop();
857+ if (thread.joinable())
858+ join();
859+}
860+
861+void mclia::InputReceiverThread::start()
862+{
863+ running = true;
864+ thread = std::thread(std::mem_fn(&mclia::InputReceiverThread::thread_loop), this);
865+}
866+
867+void mclia::InputReceiverThread::stop()
868+{
869+ running = false;
870+ receiver->wake();
871+}
872+
873+void mclia::InputReceiverThread::join()
874+{
875+ thread.join();
876+}
877+
878+void mclia::InputReceiverThread::thread_loop()
879+{
880+ while (running)
881+ {
882+ MirEvent ev;
883+ while(running && receiver->next_event(ev))
884+ handler(&ev);
885+ std::this_thread::yield(); // yield() is needed to ensure reasonable runtime under valgrind
886+ }
887+}
888
889=== added file 'src/client/input/android_input_receiver_thread.h'
890--- src/client/input/android_input_receiver_thread.h 1970-01-01 00:00:00 +0000
891+++ src/client/input/android_input_receiver_thread.h 2013-04-03 18:49:21 +0000
892@@ -0,0 +1,71 @@
893+/*
894+ * Copyright © 2013 Canonical Ltd.
895+ *
896+ * This program is free software: you can redistribute it and/or modify
897+ * it under the terms of the GNU General Public License version 3 as
898+ * published by the Free Software Foundation.
899+ *
900+ * This program is distributed in the hope that it will be useful,
901+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
902+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
903+ * GNU General Public License for more details.
904+ *
905+ * You should have received a copy of the GNU General Public License
906+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
907+ *
908+ * Authored by: Robert Carr <robert.carr@canonical.com>
909+ */
910+
911+#ifndef MIR_INPUT_ANDROID_INPUT_RECEIVER_THREAD_H_
912+#define MIR_INPUT_ANDROID_INPUT_RECEIVER_THREAD_H_
913+
914+#include "input_receiver_thread.h"
915+
916+#include "mir_toolkit/input/event.h"
917+
918+#include <functional>
919+#include <memory>
920+#include <atomic>
921+#include <thread>
922+
923+namespace mir
924+{
925+namespace client
926+{
927+namespace input
928+{
929+namespace android
930+{
931+class InputReceiver;
932+
933+/// Responsible for polling an InputReceiver to read and dispatch events when appropriate.
934+class InputReceiverThread : public input::InputReceiverThread
935+{
936+public:
937+ InputReceiverThread(std::shared_ptr<InputReceiver> const& receiver,
938+ std::function<void(MirEvent*)> const& event_handling_callback);
939+ virtual ~InputReceiverThread();
940+
941+ void start();
942+ void stop();
943+ void join();
944+
945+protected:
946+ InputReceiverThread(const InputReceiverThread&) = delete;
947+ InputReceiverThread& operator=(const InputReceiverThread&) = delete;
948+
949+private:
950+ std::shared_ptr<InputReceiver> const receiver;
951+ std::function<void(MirEvent*)> const handler;
952+
953+ void thread_loop();
954+ std::atomic<bool> running;
955+ std::thread thread;
956+};
957+
958+}
959+}
960+}
961+} // namespace mir
962+
963+#endif // MIR_INPUT_ANDROID_INPUT_RECEIVER_THREAD_H_
964
965=== added file 'src/client/input/input_platform.h'
966--- src/client/input/input_platform.h 1970-01-01 00:00:00 +0000
967+++ src/client/input/input_platform.h 2013-04-03 18:49:21 +0000
968@@ -0,0 +1,55 @@
969+/*
970+ * Copyright © 2013 Canonical Ltd.
971+ *
972+ * This program is free software: you can redistribute it and/or modify
973+ * it under the terms of the GNU General Public License version 3 as
974+ * published by the Free Software Foundation.
975+ *
976+ * This program is distributed in the hope that it will be useful,
977+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
978+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
979+ * GNU General Public License for more details.
980+ *
981+ * You should have received a copy of the GNU General Public License
982+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
983+ *
984+ * Authored by: Robert Carr <robert.carr@canonical.com>
985+ */
986+
987+#ifndef MIR_CLIENT_INPUT_PLATFORM_H_
988+#define MIR_CLIENT_INPUT_PLATFORM_H_
989+
990+#include "mir_toolkit/input/event.h"
991+
992+#include <memory>
993+#include <functional>
994+
995+namespace mir
996+{
997+namespace client
998+{
999+namespace input
1000+{
1001+class InputReceiverThread;
1002+
1003+// Interface for MirSurface to construct input dispatcher threads.
1004+class InputPlatform
1005+{
1006+public:
1007+ virtual ~InputPlatform() {};
1008+
1009+ virtual std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback) = 0;
1010+
1011+ static std::shared_ptr<InputPlatform> create();
1012+
1013+protected:
1014+ InputPlatform() = default;
1015+ InputPlatform(const InputPlatform&) = delete;
1016+ InputPlatform& operator=(const InputPlatform&) = delete;
1017+};
1018+
1019+}
1020+}
1021+} // namespace mir
1022+
1023+#endif // MIR_CLIENT_INPUT_PLATFORM_H_
1024
1025=== added file 'src/client/input/input_receiver_thread.h'
1026--- src/client/input/input_receiver_thread.h 1970-01-01 00:00:00 +0000
1027+++ src/client/input/input_receiver_thread.h 2013-04-03 18:49:21 +0000
1028@@ -0,0 +1,48 @@
1029+/*
1030+ * Copyright © 2013 Canonical Ltd.
1031+ *
1032+ * This program is free software: you can redistribute it and/or modify
1033+ * it under the terms of the GNU General Public License version 3 as
1034+ * published by the Free Software Foundation.
1035+ *
1036+ * This program is distributed in the hope that it will be useful,
1037+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1038+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1039+ * GNU General Public License for more details.
1040+ *
1041+ * You should have received a copy of the GNU General Public License
1042+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1043+ *
1044+ * Authored by: Robert Carr <robert.carr@canonical.com>
1045+ */
1046+
1047+#ifndef MIR_CLIENT_INPUT_RECEIVER_THREAD_H_
1048+#define MIR_CLIENT_INPUT_RECEIVER_THREAD_H_
1049+
1050+namespace mir
1051+{
1052+namespace client
1053+{
1054+namespace input
1055+{
1056+
1057+class InputReceiverThread
1058+{
1059+public:
1060+ virtual ~InputReceiverThread() {};
1061+
1062+ virtual void start() = 0;
1063+ virtual void stop() = 0;
1064+ virtual void join() = 0;
1065+
1066+protected:
1067+ InputReceiverThread() = default;
1068+ InputReceiverThread(const InputReceiverThread&) = delete;
1069+ InputReceiverThread& operator=(const InputReceiverThread&) = delete;
1070+};
1071+
1072+}
1073+}
1074+} // namespace mir
1075+
1076+#endif // MIR_CLIENT_INPUT_RECEIVER_THREAD_H_
1077
1078=== modified file 'src/client/mir_client_library.cpp'
1079--- src/client/mir_client_library.cpp 2013-03-29 11:27:00 +0000
1080+++ src/client/mir_client_library.cpp 2013-04-03 18:49:21 +0000
1081@@ -118,16 +118,17 @@
1082 }
1083
1084 MirWaitHandle* mir_surface_create(
1085- MirConnection * connection,
1086- MirSurfaceParameters const * params,
1087+ MirConnection* connection,
1088+ MirSurfaceParameters const* params,
1089+ MirEventDelegate const* delegate,
1090 mir_surface_lifecycle_callback callback,
1091- void * context)
1092+ void* context)
1093 {
1094 if (&error_connection == connection) return 0;
1095
1096 try
1097 {
1098- return connection->create_surface(*params, callback, context);
1099+ return connection->create_surface(*params, delegate, callback, context);
1100 }
1101 catch (std::exception const&)
1102 {
1103@@ -137,12 +138,15 @@
1104
1105 }
1106
1107-MirSurface *mir_surface_create_sync(
1108- MirConnection *connection, MirSurfaceParameters const *params)
1109+MirSurface* mir_surface_create_sync(
1110+ MirConnection* connection,
1111+ MirSurfaceParameters const* params,
1112+ MirEventDelegate const* delegate)
1113 {
1114 MirSurface *surface = nullptr;
1115
1116 mir_wait_for(mir_surface_create(connection, params,
1117+ delegate,
1118 reinterpret_cast<mir_surface_lifecycle_callback>(assign_result),
1119 &surface));
1120
1121
1122=== modified file 'src/client/mir_client_surface.h'
1123--- src/client/mir_client_surface.h 2013-03-29 11:27:00 +0000
1124+++ src/client/mir_client_surface.h 2013-04-03 18:49:21 +0000
1125@@ -22,6 +22,7 @@
1126 #include "mir_toolkit/mir_client_library.h"
1127
1128 #include <memory>
1129+
1130 namespace mir
1131 {
1132 namespace client
1133
1134=== modified file 'src/client/mir_connection.cpp'
1135--- src/client/mir_connection.cpp 2013-03-29 11:27:00 +0000
1136+++ src/client/mir_connection.cpp 2013-04-03 18:49:21 +0000
1137@@ -25,10 +25,13 @@
1138 #include "client_buffer_depository.h"
1139 #include "make_rpc_channel.h"
1140
1141+#include "input/input_platform.h"
1142+
1143 #include <thread>
1144 #include <cstddef>
1145
1146 namespace mcl = mir::client;
1147+namespace mcli = mcl::input;
1148 namespace mp = mir::protobuf;
1149 namespace gp = google::protobuf;
1150
1151@@ -46,7 +49,8 @@
1152 channel(channel),
1153 server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL),
1154 log(log),
1155- client_platform_factory(client_platform_factory)
1156+ client_platform_factory(client_platform_factory),
1157+ input_platform(mcli::InputPlatform::create())
1158 {
1159 {
1160 std::lock_guard<std::mutex> lock(connection_guard);
1161@@ -63,11 +67,13 @@
1162
1163 MirWaitHandle* MirConnection::create_surface(
1164 MirSurfaceParameters const & params,
1165+ MirEventDelegate const* delegate,
1166 mir_surface_lifecycle_callback callback,
1167 void * context)
1168 {
1169 auto null_log = std::make_shared<mir::client::NullLogger>();
1170- auto surface = new MirSurface(this, server, null_log, platform->create_buffer_factory(), params, callback, context);
1171+ auto surface = new MirSurface(this, server, null_log, platform->create_buffer_factory(), input_platform, params, delegate, callback, context);
1172+
1173 return surface->get_create_wait_handle();
1174 }
1175
1176
1177=== modified file 'src/client/mir_connection.h'
1178--- src/client/mir_connection.h 2013-04-02 09:23:02 +0000
1179+++ src/client/mir_connection.h 2013-04-03 18:49:21 +0000
1180@@ -42,6 +42,10 @@
1181 class Logger;
1182 class ClientBufferDepository;
1183 class ClientPlatformFactory;
1184+namespace input
1185+{
1186+class InputPlatform;
1187+}
1188 }
1189 }
1190
1191@@ -60,6 +64,7 @@
1192
1193 MirWaitHandle* create_surface(
1194 MirSurfaceParameters const & params,
1195+ MirEventDelegate const* delegate,
1196 mir_surface_lifecycle_callback callback,
1197 void * context);
1198 MirWaitHandle* release_surface(
1199@@ -114,6 +119,8 @@
1200 std::shared_ptr<mir::client::ClientPlatform> platform;
1201 std::shared_ptr<EGLNativeDisplayType> native_display;
1202
1203+ std::shared_ptr<mir::client::input::InputPlatform> const input_platform;
1204+
1205 std::string error_message;
1206
1207 MirWaitHandle connect_wait_handle;
1208
1209=== modified file 'src/client/mir_surface.cpp'
1210--- src/client/mir_surface.cpp 2013-04-02 09:23:02 +0000
1211+++ src/client/mir_surface.cpp 2013-04-03 18:49:21 +0000
1212@@ -21,11 +21,14 @@
1213 #include "client_buffer.h"
1214 #include "mir_surface.h"
1215 #include "mir_connection.h"
1216+#include "input/input_receiver_thread.h"
1217+#include "input/input_platform.h"
1218
1219 #include <cassert>
1220
1221 namespace geom = mir::geometry;
1222 namespace mcl = mir::client;
1223+namespace mcli = mir::client::input;
1224 namespace mp = mir::protobuf;
1225 namespace gp = google::protobuf;
1226
1227@@ -34,11 +37,14 @@
1228 mp::DisplayServer::Stub & server,
1229 std::shared_ptr<mir::client::Logger> const& logger,
1230 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
1231- MirSurfaceParameters const& params,
1232+ std::shared_ptr<mcli::InputPlatform> const& input_platform,
1233+ MirSurfaceParameters const & params,
1234+ MirEventDelegate const* delegate,
1235 mir_surface_lifecycle_callback callback, void * context)
1236 : server(server),
1237 connection(allocating_connection),
1238 buffer_depository(std::make_shared<mcl::ClientBufferDepository>(factory, 3)),
1239+ input_platform(input_platform),
1240 logger(logger)
1241 {
1242 mir::protobuf::SurfaceParameters message;
1243@@ -47,6 +53,9 @@
1244 message.set_height(params.height);
1245 message.set_pixel_format(params.pixel_format);
1246 message.set_buffer_usage(params.buffer_usage);
1247+
1248+ if (delegate)
1249+ handle_event_callback = std::bind(delegate->handle_input, this, std::placeholders::_1, delegate->context);
1250
1251 server.create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));
1252
1253@@ -57,6 +66,8 @@
1254
1255 MirSurface::~MirSurface()
1256 {
1257+ if (input_thread)
1258+ input_thread->stop();
1259 release_cpu_region();
1260 }
1261
1262@@ -166,6 +177,13 @@
1263 accelerated_window = platform->create_egl_native_window(this);
1264
1265 callback(this, context);
1266+
1267+ if (surface.fd_size() > 0 && handle_event_callback)
1268+ {
1269+ input_thread = input_platform->create_input_thread(surface.fd(0), handle_event_callback);
1270+ input_thread->start();
1271+ }
1272+
1273 create_wait_handle.result_received();
1274 }
1275
1276
1277=== modified file 'src/client/mir_surface.h'
1278--- src/client/mir_surface.h 2013-03-29 11:27:00 +0000
1279+++ src/client/mir_surface.h 2013-04-03 18:49:21 +0000
1280@@ -30,12 +30,19 @@
1281 #include "client_platform.h"
1282
1283 #include <memory>
1284+#include <functional>
1285
1286 namespace mir
1287 {
1288 namespace client
1289 {
1290 class ClientBuffer;
1291+namespace input
1292+{
1293+class InputPlatform;
1294+class InputReceiverThread;
1295+}
1296+
1297 struct MemoryRegion;
1298 }
1299 }
1300@@ -51,7 +58,9 @@
1301 mir::protobuf::DisplayServer::Stub & server,
1302 std::shared_ptr<mir::client::Logger> const& logger,
1303 std::shared_ptr<mir::client::ClientBufferFactory> const& buffer_factory,
1304+ std::shared_ptr<mir::client::input::InputPlatform> const& input_platform,
1305 MirSurfaceParameters const& params,
1306+ MirEventDelegate const* delegate,
1307 mir_surface_lifecycle_callback callback, void * context);
1308
1309 ~MirSurface();
1310@@ -97,6 +106,7 @@
1311
1312 std::shared_ptr<mir::client::MemoryRegion> secured_region;
1313 std::shared_ptr<mir::client::ClientBufferDepository> buffer_depository;
1314+ std::shared_ptr<mir::client::input::InputPlatform> const input_platform;
1315
1316 std::shared_ptr<mir::client::Logger> logger;
1317 std::shared_ptr<EGLNativeWindowType> accelerated_window;
1318@@ -105,6 +115,9 @@
1319
1320 // Cache of latest SurfaceSettings returned from the server
1321 int attrib_cache[mir_surface_attrib_arraysize_];
1322+
1323+ std::function<void(MirEvent*)> handle_event_callback;
1324+ std::shared_ptr<mir::client::input::InputReceiverThread> input_thread;
1325 };
1326
1327 #endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */
1328
1329=== modified file 'src/server/CMakeLists.txt'
1330--- src/server/CMakeLists.txt 2013-03-29 10:44:42 +0000
1331+++ src/server/CMakeLists.txt 2013-04-03 18:49:21 +0000
1332@@ -51,6 +51,7 @@
1333 mirfrontend
1334 mirgraphics
1335 mirinput
1336+ mirinputandroidtransport
1337 mirsurfaces
1338 mirtime
1339 )
1340
1341=== modified file 'src/server/default_server_configuration.cpp'
1342--- src/server/default_server_configuration.cpp 2013-03-28 14:20:06 +0000
1343+++ src/server/default_server_configuration.cpp 2013-04-03 18:49:21 +0000
1344@@ -44,6 +44,7 @@
1345 #include "mir/graphics/buffer_initializer.h"
1346 #include "mir/graphics/null_display_report.h"
1347 #include "mir/input/input_manager.h"
1348+#include "mir/input/null_input_manager.h"
1349 #include "mir/logging/logger.h"
1350 #include "mir/logging/dumb_console_logger.h"
1351 #include "mir/logging/glog_logger.h"
1352@@ -140,6 +141,7 @@
1353 "Environment variables capitalise long form with prefix \"MIR_SERVER_\" and \"_\" in place of \"-\"");
1354 desc.add_options()
1355 ("file,f", po::value<std::string>(), "Socket filename")
1356+ ("enable-input,i", po::value<bool>(), "Enable input. [bool:default=false]")
1357 (log_display, po::value<bool>(), "Log the Display report. [bool:default=false]")
1358 (log_app_mediator, po::value<bool>(), "Log the ApplicationMediator report. [bool:default=false]")
1359 (log_msg_processor, po::value<bool>(), "log the MessageProcessor report")
1360@@ -316,9 +318,12 @@
1361 mir::DefaultServerConfiguration::the_input_manager()
1362 {
1363 return input_manager(
1364- [&, this]()
1365+ [&, this]() -> std::shared_ptr<mi::InputManager>
1366 {
1367- return mi::create_input_manager(the_event_filters(), the_display());
1368+ if (the_options()->get("enable-input", false))
1369+ return mi::create_input_manager(the_event_filters(), the_display());
1370+ else
1371+ return std::make_shared<mi::NullInputManager>();
1372 });
1373 }
1374
1375
1376=== modified file 'src/server/frontend/protobuf_message_processor.cpp'
1377--- src/server/frontend/protobuf_message_processor.cpp 2013-03-22 03:33:00 +0000
1378+++ src/server/frontend/protobuf_message_processor.cpp 2013-04-03 18:49:21 +0000
1379@@ -73,12 +73,14 @@
1380
1381 void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, mir::protobuf::Surface* response)
1382 {
1383- const auto& fd = response->has_buffer() ?
1384+ auto const& surface_fd = extract_fds_from(response);
1385+ const auto& buffer_fd = response->has_buffer() ?
1386 extract_fds_from(response->mutable_buffer()) :
1387 std::vector<int32_t>();
1388
1389 send_response(id, static_cast<google::protobuf::Message*>(response));
1390- sender->send_fds(fd);
1391+ sender->send_fds(surface_fd);
1392+ sender->send_fds(buffer_fd);
1393 resource_cache->free_resource(response);
1394 }
1395
1396
1397=== modified file 'src/server/input/CMakeLists.txt'
1398--- src/server/input/CMakeLists.txt 2013-03-13 04:54:15 +0000
1399+++ src/server/input/CMakeLists.txt 2013-04-03 18:49:21 +0000
1400@@ -4,14 +4,7 @@
1401 event_filter_chain.cpp
1402 )
1403
1404-if (NOT MIR_DISABLE_INPUT)
1405 add_subdirectory(android)
1406-else()
1407-list(
1408- APPEND INPUT_SOURCES
1409- dummy_input_manager.cpp
1410-)
1411-endif()
1412
1413 add_library(
1414 mirinput STATIC
1415
1416=== modified file 'src/server/input/android/CMakeLists.txt'
1417--- src/server/input/android/CMakeLists.txt 2013-03-22 16:41:59 +0000
1418+++ src/server/input/android/CMakeLists.txt 2013-04-03 18:49:21 +0000
1419@@ -3,7 +3,6 @@
1420 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_manager.cpp
1421 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_reader_policy.cpp
1422 ${CMAKE_CURRENT_SOURCE_DIR}/android_pointer_controller.cpp
1423- ${CMAKE_CURRENT_SOURCE_DIR}/android_input_lexicon.cpp
1424 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_channel.cpp
1425 ${CMAKE_CURRENT_SOURCE_DIR}/rudimentary_input_reader_policy.cpp
1426 ${CMAKE_CURRENT_SOURCE_DIR}/event_filter_dispatcher_policy.cpp
1427@@ -18,3 +17,4 @@
1428 PARENT_SCOPE
1429 )
1430
1431+add_subdirectory(transport)
1432
1433=== modified file 'src/server/input/android/android_input_application_handle.cpp'
1434--- src/server/input/android/android_input_application_handle.cpp 2013-03-20 22:42:09 +0000
1435+++ src/server/input/android/android_input_application_handle.cpp 2013-04-03 18:49:21 +0000
1436@@ -26,7 +26,7 @@
1437 namespace mia = mi::android;
1438
1439 mia::InputApplicationHandle::InputApplicationHandle(std::shared_ptr<mi::SessionTarget> const& session)
1440- : session(session)
1441+ : weak_session(session)
1442 {
1443 updateInfo();
1444 }
1445@@ -35,6 +35,11 @@
1446 {
1447 if (mInfo == NULL)
1448 mInfo = new droidinput::InputApplicationInfo;
1449+
1450+ auto session = weak_session.lock();
1451+ if (!session)
1452+ return false;
1453+
1454 mInfo->dispatchingTimeout = INT_MAX;
1455 mInfo->name = droidinput::String8(session->name().c_str());
1456
1457
1458=== modified file 'src/server/input/android/android_input_application_handle.h'
1459--- src/server/input/android/android_input_application_handle.h 2013-03-20 22:42:09 +0000
1460+++ src/server/input/android/android_input_application_handle.h 2013-04-03 18:49:21 +0000
1461@@ -48,7 +48,7 @@
1462 InputApplicationHandle& operator=(InputApplicationHandle const&) = delete;
1463
1464 private:
1465- std::shared_ptr<input::SessionTarget> session;
1466+ std::weak_ptr<input::SessionTarget> weak_session;
1467 };
1468
1469 }
1470
1471=== modified file 'src/server/input/android/event_filter_dispatcher_policy.cpp'
1472--- src/server/input/android/event_filter_dispatcher_policy.cpp 2013-03-22 16:41:59 +0000
1473+++ src/server/input/android/event_filter_dispatcher_policy.cpp 2013-04-03 18:49:21 +0000
1474@@ -16,10 +16,11 @@
1475 * Authored by: Robert Carr <robert.carr@canonical.com>
1476 */
1477 #include "event_filter_dispatcher_policy.h"
1478-#include "android_input_lexicon.h"
1479+#include "mir/input/android/android_input_lexicon.h"
1480
1481 namespace mi = mir::input;
1482 namespace mia = mi::android;
1483+namespace miat = mia::transport;
1484
1485 mia::EventFilterDispatcherPolicy::EventFilterDispatcherPolicy(std::shared_ptr<mi::EventFilter> const& event_filter) :
1486 event_filter(event_filter)
1487@@ -29,7 +30,7 @@
1488 bool mia::EventFilterDispatcherPolicy::filterInputEvent(const droidinput::InputEvent* input_event, uint32_t /*policy_flags*/)
1489 {
1490 MirEvent mir_ev;
1491- mia::Lexicon::translate(input_event, mir_ev);
1492+ miat::Lexicon::translate(input_event, mir_ev);
1493
1494 if (event_filter->handles(mir_ev))
1495 return false; /* Do not pass the event on */
1496
1497=== added directory 'src/server/input/android/transport'
1498=== added file 'src/server/input/android/transport/CMakeLists.txt'
1499--- src/server/input/android/transport/CMakeLists.txt 1970-01-01 00:00:00 +0000
1500+++ src/server/input/android/transport/CMakeLists.txt 2013-04-03 18:49:21 +0000
1501@@ -0,0 +1,31 @@
1502+# Copyright © 2012 Canonical Ltd.
1503+#
1504+# This program is free software: you can redistribute it and/or modify
1505+# it under the terms of the GNU General Public License version 3 as
1506+# published by the Free Software Foundation.
1507+#
1508+# This program is distributed in the hope that it will be useful,
1509+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1510+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1511+# GNU General Public License for more details.
1512+#
1513+# You should have received a copy of the GNU General Public License
1514+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515+#
1516+# Authored by: Thomas Voss <thomas.voss@canonical.com>
1517+
1518+set(
1519+ ANDROID_TRANSPORT_SOURCES
1520+ ${CMAKE_CURRENT_SOURCE_DIR}/android_input_lexicon.cpp
1521+)
1522+
1523+add_library(
1524+ mirinputandroidtransport STATIC
1525+ ${ANDROID_TRANSPORT_SOURCES}
1526+)
1527+
1528+target_link_libraries(
1529+ mirinputandroidtransport
1530+
1531+ android-input
1532+)
1533
1534=== renamed file 'src/server/input/android/android_input_lexicon.cpp' => 'src/server/input/android/transport/android_input_lexicon.cpp'
1535--- src/server/input/android/android_input_lexicon.cpp 2013-03-13 04:54:15 +0000
1536+++ src/server/input/android/transport/android_input_lexicon.cpp 2013-04-03 18:49:21 +0000
1537@@ -1,29 +1,29 @@
1538 /*
1539 * Copyright © 2012 Canonical Ltd.
1540 *
1541- * This program is free software: you can redistribute it and/or modify it
1542- * under the terms of the GNU Lesser General Public License version 3,
1543- * as published by the Free Software Foundation.
1544+ * This program is free software: you can redistribute it and/or modify
1545+ * it under the terms of the GNU General Public License version 3 as
1546+ * published by the Free Software Foundation.
1547 *
1548 * This program is distributed in the hope that it will be useful,
1549 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1550 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1551 * GNU General Public License for more details.
1552 *
1553- * You should have received a copy of the GNU Lesser General Public License
1554+ * You should have received a copy of the GNU General Public License
1555 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1556 *
1557 * Authored by: Thomas Voss <thomas.voss@canonical.com>
1558 * Robert Carr <robert.carr@canonical.com>
1559 */
1560
1561-#include "android_input_lexicon.h"
1562+#include "mir/input/android/android_input_lexicon.h"
1563
1564 #include <androidfw/Input.h>
1565
1566-namespace mia = mir::input::android;
1567+namespace miat = mir::input::android::transport;
1568
1569-void mia::Lexicon::translate(const droidinput::InputEvent *android_event, MirEvent &mir_event)
1570+void miat::Lexicon::translate(const droidinput::InputEvent *android_event, MirEvent &mir_event)
1571 {
1572 switch(android_event->getType())
1573 {
1574
1575=== removed file 'src/server/input/dummy_input_manager.cpp'
1576--- src/server/input/dummy_input_manager.cpp 2013-03-29 16:51:35 +0000
1577+++ src/server/input/dummy_input_manager.cpp 1970-01-01 00:00:00 +0000
1578@@ -1,42 +0,0 @@
1579-/*
1580- * Copyright © 2012 Canonical Ltd.
1581- *
1582- * This program is free software: you can redistribute it and/or modify it
1583- * under the terms of the GNU Lesser General Public License version 3,
1584- * as published by the Free Software Foundation.
1585- *
1586- * This program is distributed in the hope that it will be useful,
1587- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1588- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1589- * GNU General Public License for more details.
1590- *
1591- * You should have received a copy of the GNU Lesser General Public License
1592- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1593- *
1594- * Authored by: Alan Griffiths <alan@octopull.co.uk>
1595- */
1596-
1597-#include "mir/input/input_manager.h"
1598-
1599-namespace mg = mir::graphics;
1600-namespace mi = mir::input;
1601-
1602-namespace
1603-{
1604-class DummyInputManager : public mi::InputManager
1605-{
1606- void stop() {}
1607- void start() {}
1608- virtual std::shared_ptr<mi::InputChannel> make_input_channel() { return std::shared_ptr<mi::InputChannel>(); }
1609- void set_input_focus_to(std::shared_ptr<mi::SessionTarget> const& /* session */, std::shared_ptr<mi::SurfaceTarget> const& /* surface */)
1610- {
1611- }
1612-};
1613-}
1614-
1615-std::shared_ptr<mi::InputManager> mi::create_input_manager(
1616- const std::initializer_list<std::shared_ptr<mi::EventFilter> const>& ,
1617- std::shared_ptr<mg::ViewableArea> const& )
1618-{
1619- return std::make_shared<DummyInputManager>();
1620-}
1621
1622=== modified file 'tests/acceptance-tests/CMakeLists.txt'
1623--- tests/acceptance-tests/CMakeLists.txt 2013-03-29 22:30:35 +0000
1624+++ tests/acceptance-tests/CMakeLists.txt 2013-04-03 18:49:21 +0000
1625@@ -13,6 +13,9 @@
1626 )
1627
1628 list(APPEND SOURCES
1629+ test_client_input.cpp)
1630+
1631+list(APPEND SOURCES
1632 test_server_startup.cpp
1633 )
1634
1635@@ -21,6 +24,7 @@
1636
1637 ${SOURCES}
1638 )
1639+uses_android_input(acceptance-tests)
1640
1641
1642 target_link_libraries(
1643
1644=== added file 'tests/acceptance-tests/test_client_input.cpp'
1645--- tests/acceptance-tests/test_client_input.cpp 1970-01-01 00:00:00 +0000
1646+++ tests/acceptance-tests/test_client_input.cpp 2013-04-03 18:49:21 +0000
1647@@ -0,0 +1,268 @@
1648+/*
1649+ * Copyright © 2013 Canonical Ltd.
1650+ *
1651+ * This program is free software: you can redistribute it and/or modify
1652+ * it under the terms of the GNU General Public License version 3 as
1653+ * published by the Free Software Foundation.
1654+ *
1655+ * This program is distributed in the hope that it will be useful,
1656+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1657+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1658+ * GNU General Public License for more details.
1659+ *
1660+ * You should have received a copy of the GNU General Public License
1661+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1662+ *
1663+ * Authored by: Robert Carr <robert.carr@canonical.com>
1664+ */
1665+
1666+#include "mir/graphics/display.h"
1667+
1668+#include "src/server/input/android/android_input_manager.h"
1669+
1670+#include "mir_toolkit/mir_client_library.h"
1671+
1672+#include "mir_test/fake_shared.h"
1673+#include "mir_test/fake_event_hub_input_configuration.h"
1674+#include "mir_test/fake_event_hub.h"
1675+#include "mir_test/event_factory.h"
1676+#include "mir_test/wait_condition.h"
1677+#include "mir_test_framework/display_server_test_fixture.h"
1678+
1679+#include <gtest/gtest.h>
1680+#include <gmock/gmock.h>
1681+
1682+#include <thread>
1683+#include <functional>
1684+
1685+namespace mi = mir::input;
1686+namespace mia = mi::android;
1687+namespace mis = mi::synthesis;
1688+namespace mt = mir::test;
1689+namespace mtd = mt::doubles;
1690+namespace mtf = mir_test_framework;
1691+
1692+namespace
1693+{
1694+ char const* const mir_test_socket = mtf::test_socket_file().c_str();
1695+}
1696+
1697+namespace
1698+{
1699+
1700+struct FocusNotifyingInputManager : public mia::InputManager
1701+{
1702+ FocusNotifyingInputManager(std::shared_ptr<mia::InputConfiguration> const& configuration,
1703+ mt::WaitCondition &wait_condition)
1704+ : InputManager(configuration),
1705+ on_focus_set(wait_condition)
1706+ {
1707+
1708+ }
1709+
1710+ void set_input_focus_to(
1711+ std::shared_ptr<mi::SessionTarget> const& session, std::shared_ptr<mi::SurfaceTarget> const& surface) override
1712+ {
1713+ InputManager::set_input_focus_to(session, surface);
1714+
1715+ // We need a synchronization primitive inorder to halt test event injection
1716+ // until after a surface has taken focus (lest the events be discarded).
1717+ if (surface)
1718+ on_focus_set.wake_up_everyone();
1719+ }
1720+
1721+ mt::WaitCondition &on_focus_set;
1722+};
1723+
1724+struct FakeInputServerConfiguration : public mir_test_framework::TestingServerConfiguration
1725+{
1726+ FakeInputServerConfiguration()
1727+ : input_config(the_event_filters(), the_display(), std::shared_ptr<mi::CursorListener>())
1728+ {
1729+ }
1730+
1731+ virtual void inject_input()
1732+ {
1733+ }
1734+
1735+ void exec(mir::DisplayServer* /* display_server */) override
1736+ {
1737+ input_injection_thread = std::thread([this]() -> void
1738+ {
1739+ on_focus_set.wait_for_at_most_seconds(10);
1740+ fake_event_hub->synthesize_builtin_keyboard_added();
1741+ fake_event_hub->synthesize_device_scan_complete();
1742+ inject_input();
1743+ });
1744+ }
1745+
1746+ void on_exit() override
1747+ {
1748+ input_injection_thread.join();
1749+ }
1750+
1751+ std::shared_ptr<mi::InputManager>
1752+ the_input_manager() override
1753+ {
1754+ fake_event_hub = input_config.the_fake_event_hub();
1755+
1756+ return input_manager(
1757+ [this]() -> std::shared_ptr<mi::InputManager>
1758+ {
1759+ return std::make_shared<FocusNotifyingInputManager>(mt::fake_shared(input_config), on_focus_set);
1760+ });
1761+ }
1762+
1763+ mtd::FakeEventHubInputConfiguration input_config;
1764+ mia::FakeEventHub* fake_event_hub;
1765+ mt::WaitCondition on_focus_set;
1766+ std::thread input_injection_thread;
1767+};
1768+
1769+
1770+struct ClientConfigCommon : TestingClientConfiguration
1771+{
1772+ ClientConfigCommon() :
1773+ connection(0),
1774+ surface(0)
1775+ {
1776+ }
1777+
1778+ static void connection_callback(MirConnection* connection, void* context)
1779+ {
1780+ ClientConfigCommon* config = reinterpret_cast<ClientConfigCommon *>(context);
1781+ config->connection = connection;
1782+ }
1783+
1784+ static void create_surface_callback(MirSurface* surface, void* context)
1785+ {
1786+ ClientConfigCommon* config = reinterpret_cast<ClientConfigCommon *>(context);
1787+ config->surface_created(surface);
1788+ }
1789+
1790+ static void release_surface_callback(MirSurface* surface, void* context)
1791+ {
1792+ ClientConfigCommon* config = reinterpret_cast<ClientConfigCommon *>(context);
1793+ config->surface_released(surface);
1794+ }
1795+
1796+ virtual void connected(MirConnection* new_connection)
1797+ {
1798+ connection = new_connection;
1799+ }
1800+
1801+ virtual void surface_created(MirSurface* new_surface)
1802+ {
1803+ surface = new_surface;
1804+ }
1805+
1806+ virtual void surface_released(MirSurface* /* released_surface */)
1807+ {
1808+ surface = NULL;
1809+ }
1810+
1811+ MirConnection* connection;
1812+ MirSurface* surface;
1813+};
1814+
1815+struct MockInputHandler
1816+{
1817+ MOCK_METHOD1(handle_input, void(MirEvent *));
1818+};
1819+
1820+struct InputReceivingClient : ClientConfigCommon
1821+{
1822+ InputReceivingClient()
1823+ : events_received(0)
1824+ {
1825+ }
1826+
1827+ static void handle_input(MirSurface* /* surface */, MirEvent* ev, void* context)
1828+ {
1829+ auto client = static_cast<InputReceivingClient *>(context);
1830+ client->handler->handle_input(ev);
1831+ client->event_received[client->events_received].wake_up_everyone();
1832+ client->events_received++;
1833+ }
1834+ virtual void expect_input()
1835+ {
1836+ }
1837+
1838+ void exec()
1839+ {
1840+ handler = std::make_shared<MockInputHandler>();
1841+
1842+ expect_input();
1843+
1844+ mir_wait_for(mir_connect(
1845+ mir_test_socket,
1846+ __PRETTY_FUNCTION__,
1847+ connection_callback,
1848+ this));
1849+ ASSERT_TRUE(connection != NULL);
1850+ MirSurfaceParameters const request_params =
1851+ {
1852+ __PRETTY_FUNCTION__,
1853+ 640, 480,
1854+ mir_pixel_format_abgr_8888,
1855+ mir_buffer_usage_hardware
1856+ };
1857+ MirEventDelegate const event_delegate =
1858+ {
1859+ handle_input,
1860+ this
1861+ };
1862+ mir_wait_for(mir_surface_create(connection, &request_params, &event_delegate, create_surface_callback, this));
1863+
1864+ event_received[0].wait_for_at_most_seconds(5);
1865+ event_received[1].wait_for_at_most_seconds(5);
1866+ event_received[2].wait_for_at_most_seconds(5);
1867+
1868+ mir_surface_release_sync(surface);
1869+
1870+ mir_connection_release(connection);
1871+
1872+ // ClientConfiguration d'tor is not called on client side so we need this
1873+ // in order to not leak the Mock object.
1874+ handler.reset();
1875+ }
1876+
1877+ std::shared_ptr<MockInputHandler> handler;
1878+ mt::WaitCondition event_received[3];
1879+ int events_received;
1880+};
1881+
1882+}
1883+
1884+using TestClientInput = BespokeDisplayServerTestFixture;
1885+
1886+TEST_F(TestClientInput, clients_receive_key_input)
1887+{
1888+ using namespace ::testing;
1889+
1890+ int const num_events_produced = 3;
1891+
1892+ struct InputProducingServerConfiguration : FakeInputServerConfiguration
1893+ {
1894+ void inject_input()
1895+ {
1896+ // We send multiple events in order to verify the client is handling them
1897+ // and server dispatch does not become backed up.
1898+ for (int i = 0; i < num_events_produced; i++)
1899+ fake_event_hub->synthesize_event(mis::a_key_down_event()
1900+ .of_scancode(KEY_ENTER));
1901+ }
1902+ } server_config;
1903+ launch_server_process(server_config);
1904+
1905+ struct KeyReceivingClient : InputReceivingClient
1906+ {
1907+ void expect_input()
1908+ {
1909+ using namespace ::testing;
1910+ EXPECT_CALL(*handler, handle_input(_)).Times(num_events_produced);
1911+ }
1912+ } client_config;
1913+ launch_client_process(client_config);
1914+}
1915+
1916
1917=== modified file 'tests/acceptance-tests/test_client_library.cpp'
1918--- tests/acceptance-tests/test_client_library.cpp 2013-03-22 10:34:16 +0000
1919+++ tests/acceptance-tests/test_client_library.cpp 2013-04-03 18:49:21 +0000
1920@@ -164,7 +164,7 @@
1921 mir_buffer_usage_hardware
1922 };
1923
1924- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
1925+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
1926
1927 ASSERT_TRUE(surface != NULL);
1928 EXPECT_TRUE(mir_surface_is_valid(surface));
1929@@ -182,7 +182,7 @@
1930
1931 ASSERT_TRUE(surface == NULL);
1932
1933- surface = mir_surface_create_sync(connection, &request_params);
1934+ surface = mir_surface_create_sync(connection, &request_params, NULL);
1935
1936 ASSERT_TRUE(surface != NULL);
1937 EXPECT_TRUE(mir_surface_is_valid(surface));
1938@@ -226,7 +226,7 @@
1939 mir_buffer_usage_hardware
1940 };
1941
1942- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
1943+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
1944
1945 ASSERT_TRUE(surface != NULL);
1946 EXPECT_TRUE(mir_surface_is_valid(surface));
1947@@ -329,7 +329,7 @@
1948 mir_buffer_usage_hardware
1949 };
1950
1951- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
1952+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
1953
1954 ASSERT_EQ(old_surface_count + 1, current_surface_count());
1955 }
1956@@ -377,7 +377,7 @@
1957 mir_buffer_usage_hardware
1958 };
1959
1960- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
1961+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
1962 ASSERT_TRUE(surface != NULL);
1963
1964 buffers = 0;
1965@@ -416,7 +416,7 @@
1966 mir_buffer_usage_software
1967 };
1968
1969- surface = mir_surface_create_sync(connection, &request_params);
1970+ surface = mir_surface_create_sync(connection, &request_params, NULL);
1971 ASSERT_TRUE(surface != NULL);
1972 EXPECT_TRUE(mir_surface_is_valid(surface));
1973 EXPECT_STREQ(mir_surface_get_error_message(surface), "");
1974@@ -524,7 +524,7 @@
1975 mir_buffer_usage_hardware
1976 };
1977
1978- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
1979+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
1980 // TODO surface_create needs to fail safe too. After that is done we should add the following:
1981 // TODO mir_wait_for(mir_surface_next_buffer(surface, next_buffer_callback, this));
1982 // TODO mir_wait_for(mir_surface_release( surface, release_surface_callback, this));
1983
1984=== modified file 'tests/acceptance-tests/test_focus_management_api.cpp'
1985--- tests/acceptance-tests/test_focus_management_api.cpp 2013-03-22 10:34:16 +0000
1986+++ tests/acceptance-tests/test_focus_management_api.cpp 2013-04-03 18:49:21 +0000
1987@@ -226,7 +226,7 @@
1988 mir_buffer_usage_hardware
1989 };
1990
1991- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
1992+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
1993
1994 set_flag(focus_ready);
1995
1996
1997=== modified file 'tests/acceptance-tests/test_focus_selection.cpp'
1998--- tests/acceptance-tests/test_focus_selection.cpp 2013-03-29 16:51:35 +0000
1999+++ tests/acceptance-tests/test_focus_selection.cpp 2013-04-03 18:49:21 +0000
2000@@ -108,7 +108,7 @@
2001 mir_pixel_format_abgr_8888,
2002 mir_buffer_usage_hardware
2003 };
2004- mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));
2005+ mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
2006 mir_connection_release(connection);
2007 }
2008 };
2009
2010=== modified file 'tests/acceptance-tests/test_surfaceloop.cpp'
2011--- tests/acceptance-tests/test_surfaceloop.cpp 2013-03-22 10:34:16 +0000
2012+++ tests/acceptance-tests/test_surfaceloop.cpp 2013-04-03 18:49:21 +0000
2013@@ -172,13 +172,13 @@
2014 mir_buffer_usage_hardware
2015 };
2016
2017- mir_surface_create(connection, &request_params, create_surface_callback, ssync);
2018+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
2019 wait_for_surface_create(ssync);
2020
2021 request_params.width = 1600;
2022 request_params.height = 1200;
2023
2024- mir_surface_create(connection, &request_params, create_surface_callback, ssync+1);
2025+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+1);
2026 wait_for_surface_create(ssync+1);
2027
2028 MirSurfaceParameters response_params;
2029@@ -225,13 +225,13 @@
2030 mir_buffer_usage_hardware
2031 };
2032
2033- mir_surface_create(connection, &request_params, create_surface_callback, ssync);
2034+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
2035 wait_for_surface_create(ssync);
2036
2037 request_params.width = 1600;
2038 request_params.height = 1200;
2039
2040- mir_surface_create(connection, &request_params, create_surface_callback, ssync+1);
2041+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+1);
2042 wait_for_surface_create(ssync+1);
2043
2044 EXPECT_NE(
2045@@ -270,7 +270,7 @@
2046 };
2047
2048 for (int i = 0; i != max_surface_count; ++i)
2049- mir_surface_create(connection, &request_params, create_surface_callback, ssync+i);
2050+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+i);
2051
2052 for (int i = 0; i != max_surface_count; ++i)
2053 wait_for_surface_create(ssync+i);
2054
2055=== modified file 'tests/integration-tests/CMakeLists.txt'
2056--- tests/integration-tests/CMakeLists.txt 2013-03-29 22:30:35 +0000
2057+++ tests/integration-tests/CMakeLists.txt 2013-04-03 18:49:21 +0000
2058@@ -12,9 +12,7 @@
2059 add_subdirectory(frontend/)
2060 add_subdirectory(shell/)
2061 add_subdirectory(process/)
2062-if (NOT MIR_DISABLE_INPUT)
2063 add_subdirectory(input/)
2064-endif()
2065
2066 if (MIR_PLATFORM STREQUAL "android")
2067 include_directories(${PROJECT_SOURCE_DIR}/include/accessory)
2068
2069=== modified file 'tests/integration-tests/client/test_client_render.cpp'
2070--- tests/integration-tests/client/test_client_render.cpp 2013-03-29 16:51:35 +0000
2071+++ tests/integration-tests/client/test_client_render.cpp 2013-04-03 18:49:21 +0000
2072@@ -102,8 +102,8 @@
2073 surface_parameters.width = test_width;
2074 surface_parameters.height = test_height;
2075 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
2076- mir_wait_for(mir_surface_create( connection, &surface_parameters,
2077- &create_callback, &surface));
2078+ mir_wait_for(mir_surface_create(connection, &surface_parameters,
2079+ NULL, &create_callback, &surface));
2080
2081 auto graphics_region = std::make_shared<MirGraphicsRegion>();
2082 /* grab a buffer*/
2083@@ -143,8 +143,8 @@
2084 surface_parameters.height = test_height;
2085 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
2086
2087- mir_wait_for(mir_surface_create( connection, &surface_parameters,
2088- &create_callback, &surface));
2089+ mir_wait_for(mir_surface_create(connection, &surface_parameters,
2090+ NULL, &create_callback, &surface));
2091
2092 auto graphics_region = std::make_shared<MirGraphicsRegion>();
2093 mir_surface_get_graphics_region( surface, graphics_region.get());
2094@@ -187,8 +187,8 @@
2095 surface_parameters.height = test_height;
2096 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
2097
2098- mir_wait_for(mir_surface_create( connection, &surface_parameters,
2099- &create_callback, &surface));
2100+ mir_wait_for(mir_surface_create(connection, &surface_parameters,
2101+ NULL, &create_callback, &surface));
2102
2103 int major, minor, n;
2104 EGLDisplay disp;
2105@@ -249,8 +249,8 @@
2106 surface_parameters.height = test_height;
2107 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
2108
2109- mir_wait_for(mir_surface_create( connection, &surface_parameters,
2110- &create_callback, &surface));
2111+ mir_wait_for(mir_surface_create(connection, &surface_parameters,
2112+ NULL, &create_callback, &surface));
2113
2114 int major, minor, n;
2115 EGLDisplay disp;
2116
2117=== modified file 'tests/integration-tests/input/android/test_android_cursor_listener.cpp'
2118--- tests/integration-tests/input/android/test_android_cursor_listener.cpp 2013-03-13 08:09:52 +0000
2119+++ tests/integration-tests/input/android/test_android_cursor_listener.cpp 2013-04-03 18:49:21 +0000
2120@@ -44,7 +44,6 @@
2121 namespace mtd = mir::test::doubles;
2122
2123 using mtd::MockEventFilter;
2124-using mir::WaitCondition;
2125
2126 namespace
2127 {
2128@@ -100,7 +99,7 @@
2129 {
2130 using namespace ::testing;
2131
2132- auto wait_condition = std::make_shared<WaitCondition>();
2133+ auto wait_condition = std::make_shared<mt::WaitCondition>();
2134
2135 static const float x = 100.f;
2136 static const float y = 100.f;
2137@@ -109,7 +108,7 @@
2138
2139 // The stack doesn't like shutting down while events are still moving through
2140 EXPECT_CALL(event_filter, handles(_))
2141- .WillOnce(ReturnFalseAndWakeUp(wait_condition));
2142+ .WillOnce(mt::ReturnFalseAndWakeUp(wait_condition));
2143
2144 fake_event_hub->synthesize_builtin_cursor_added();
2145 fake_event_hub->synthesize_device_scan_complete();
2146
2147=== modified file 'tests/integration-tests/input/android/test_android_input_manager.cpp'
2148--- tests/integration-tests/input/android/test_android_input_manager.cpp 2013-04-02 16:40:08 +0000
2149+++ tests/integration-tests/input/android/test_android_input_manager.cpp 2013-04-03 18:49:21 +0000
2150@@ -53,7 +53,6 @@
2151 namespace mtd = mir::test::doubles;
2152
2153 using mtd::MockEventFilter;
2154-using mir::WaitCondition;
2155
2156 namespace
2157 {
2158@@ -100,13 +99,13 @@
2159 {
2160 using namespace ::testing;
2161
2162- WaitCondition wait_condition;
2163+ mt::WaitCondition wait_condition;
2164
2165 EXPECT_CALL(
2166 event_filter,
2167 handles(mt::KeyDownEvent()))
2168 .Times(1)
2169- .WillOnce(ReturnFalseAndWakeUp(&wait_condition));
2170+ .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
2171
2172 fake_event_hub->synthesize_builtin_keyboard_added();
2173 fake_event_hub->synthesize_device_scan_complete();
2174@@ -121,13 +120,13 @@
2175 {
2176 using namespace ::testing;
2177
2178- WaitCondition wait_condition;
2179+ mt::WaitCondition wait_condition;
2180
2181 EXPECT_CALL(
2182 event_filter,
2183 handles(mt::ButtonDownEvent()))
2184 .Times(1)
2185- .WillOnce(ReturnFalseAndWakeUp(&wait_condition));
2186+ .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
2187
2188 fake_event_hub->synthesize_builtin_cursor_added();
2189 fake_event_hub->synthesize_device_scan_complete();
2190@@ -141,7 +140,7 @@
2191 {
2192 using namespace ::testing;
2193
2194- WaitCondition wait_condition;
2195+ mt::WaitCondition wait_condition;
2196
2197 // We get absolute motion events since we have a pointer controller.
2198 {
2199@@ -152,7 +151,7 @@
2200 .WillOnce(Return(false));
2201 EXPECT_CALL(event_filter,
2202 handles(mt::MotionEvent(200, 100)))
2203- .WillOnce(ReturnFalseAndWakeUp(&wait_condition));
2204+ .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
2205 }
2206
2207 fake_event_hub->synthesize_builtin_cursor_added();
2208@@ -253,7 +252,7 @@
2209 {
2210 using namespace ::testing;
2211
2212- WaitCondition wait_condition;
2213+ mt::WaitCondition wait_condition;
2214
2215 mtd::StubSessionTarget session;
2216 mtd::StubSurfaceTarget surface(test_input_fd);
2217@@ -261,7 +260,7 @@
2218 EXPECT_CALL(event_filter, handles(_)).Times(1).WillOnce(Return(false));
2219 // We return -1 here to skip publishing of the event (to an unconnected test socket!).
2220 EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(test_input_fd), _, _))
2221- .Times(1).WillOnce(DoAll(WakeUp(&wait_condition), Return(-1)));
2222+ .Times(1).WillOnce(DoAll(mt::WakeUp(&wait_condition), Return(-1)));
2223
2224 input_manager->set_input_focus_to(mt::fake_shared(session), mt::fake_shared(surface));
2225
2226
2227=== modified file 'tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp'
2228--- tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp 2013-04-02 16:40:08 +0000
2229+++ tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp 2013-04-03 18:49:21 +0000
2230@@ -95,16 +95,15 @@
2231 }
2232
2233 using mir::FakeEventHubSetup;
2234-using mir::WaitCondition;
2235
2236 TEST_F(FakeEventHubSetup, fake_event_hub_dispatches_to_filter)
2237 {
2238 using namespace ::testing;
2239
2240- mir::WaitCondition wait_condition;
2241+ mt::WaitCondition wait_condition;
2242
2243 EXPECT_CALL(event_filter, handles(mt::KeyDownEvent())).Times(1)
2244- .WillOnce(ReturnFalseAndWakeUp(&wait_condition));
2245+ .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
2246
2247 event_hub->synthesize_builtin_keyboard_added();
2248 event_hub->synthesize_device_scan_complete();
2249
2250=== modified file 'tests/integration-tests/test_error_reporting.cpp'
2251--- tests/integration-tests/test_error_reporting.cpp 2013-03-22 10:34:16 +0000
2252+++ tests/integration-tests/test_error_reporting.cpp 2013-04-03 18:49:21 +0000
2253@@ -238,7 +238,7 @@
2254 mir_buffer_usage_hardware
2255 };
2256
2257- mir_surface_create(connection, &request_params, create_surface_callback, ssync);
2258+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
2259
2260 wait_for_surface_create(ssync);
2261
2262
2263=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
2264--- tests/integration-tests/test_surfaceloop.cpp 2013-03-25 10:18:17 +0000
2265+++ tests/integration-tests/test_surfaceloop.cpp 2013-04-03 18:49:21 +0000
2266@@ -286,7 +286,7 @@
2267 mir_buffer_usage_hardware
2268 };
2269
2270- mir_surface_create(connection, &request_params, create_surface_callback, ssync);
2271+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
2272
2273 wait_for_surface_create(ssync);
2274
2275@@ -388,7 +388,7 @@
2276 mir_pixel_format_abgr_8888,
2277 mir_buffer_usage_hardware
2278 };
2279- mir_surface_create(connection, &request_params, create_surface_callback, ssync);
2280+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
2281
2282 wait_for_surface_create(ssync);
2283
2284@@ -522,7 +522,7 @@
2285 };
2286
2287 for (int i = 0; i != max_surface_count; ++i)
2288- mir_surface_create(connection, &request_params, create_surface_callback, ssync+i);
2289+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+i);
2290
2291 for (int i = 0; i != max_surface_count; ++i)
2292 wait_for_surface_create(ssync+i);
2293@@ -571,7 +571,7 @@
2294 };
2295
2296 for (int i = 0; i != max_surface_count; ++i)
2297- mir_surface_create(connection, &request_params, create_surface_callback, ssync+i);
2298+ mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+i);
2299
2300 for (int i = 0; i != max_surface_count; ++i)
2301 wait_for_surface_create(ssync+i);
2302
2303=== modified file 'tests/mir_test_doubles/CMakeLists.txt'
2304--- tests/mir_test_doubles/CMakeLists.txt 2013-03-28 09:50:09 +0000
2305+++ tests/mir_test_doubles/CMakeLists.txt 2013-04-03 18:49:21 +0000
2306@@ -10,12 +10,10 @@
2307 event_factory.cpp
2308 )
2309
2310-if (NOT MIR_DISABLE_INPUT)
2311 list(APPEND TEST_UTILS_SRCS
2312 fake_event_hub.cpp
2313 fake_event_hub_input_configuration.cpp
2314 )
2315-endif()
2316
2317 list(APPEND TEST_UTILS_SRCS
2318 test_protobuf_socket_server.cpp
2319
2320=== modified file 'tests/unit-tests/CMakeLists.txt'
2321--- tests/unit-tests/CMakeLists.txt 2013-03-29 22:30:35 +0000
2322+++ tests/unit-tests/CMakeLists.txt 2013-04-03 18:49:21 +0000
2323@@ -11,11 +11,8 @@
2324 add_subdirectory(shell/)
2325 add_subdirectory(geometry/)
2326 add_subdirectory(graphics/)
2327-#TODO stubbed out to run tests on emulator
2328-if (NOT MIR_DISABLE_INPUT)
2329 add_subdirectory(input/)
2330 add_subdirectory(android_input/)
2331-endif()
2332 add_subdirectory(surfaces/)
2333 add_subdirectory(draw/)
2334
2335
2336=== modified file 'tests/unit-tests/client/CMakeLists.txt'
2337--- tests/unit-tests/client/CMakeLists.txt 2013-03-24 23:33:49 +0000
2338+++ tests/unit-tests/client/CMakeLists.txt 2013-04-03 18:49:21 +0000
2339@@ -16,4 +16,8 @@
2340 add_subdirectory("gbm")
2341 endif()
2342
2343+if (NOT MIR_DISABLE_INPUT)
2344+add_subdirectory("input")
2345+endif()
2346+
2347 set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE)
2348
2349=== added directory 'tests/unit-tests/client/input'
2350=== added file 'tests/unit-tests/client/input/CMakeLists.txt'
2351--- tests/unit-tests/client/input/CMakeLists.txt 1970-01-01 00:00:00 +0000
2352+++ tests/unit-tests/client/input/CMakeLists.txt 2013-04-03 18:49:21 +0000
2353@@ -0,0 +1,9 @@
2354+list(APPEND UNIT_TEST_SOURCES
2355+ ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_receiver_thread.cpp
2356+ ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_receiver.cpp
2357+)
2358+
2359+set(
2360+ UNIT_TEST_SOURCES
2361+ ${UNIT_TEST_SOURCES}
2362+ PARENT_SCOPE)
2363
2364=== added file 'tests/unit-tests/client/input/test_android_input_receiver.cpp'
2365--- tests/unit-tests/client/input/test_android_input_receiver.cpp 1970-01-01 00:00:00 +0000
2366+++ tests/unit-tests/client/input/test_android_input_receiver.cpp 2013-04-03 18:49:21 +0000
2367@@ -0,0 +1,198 @@
2368+/*
2369+ * Copyright © 2013 Canonical Ltd.
2370+ *
2371+ * This program is free software: you can redistribute it and/or modify
2372+ * it under the terms of the GNU General Public License version 3 as
2373+ * published by the Free Software Foundation.
2374+ *
2375+ * This program is distributed in the hope that it will be useful,
2376+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2377+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2378+ * GNU General Public License for more details.
2379+ *
2380+ * You should have received a copy of the GNU General Public License
2381+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2382+ *
2383+ * Authored by: Robert Carr <robert.carr@canonical.com>
2384+ */
2385+
2386+#include "src/client/input/android_input_receiver.h"
2387+#include "mir_toolkit/input/event.h"
2388+
2389+#include <androidfw/InputTransport.h>
2390+
2391+#include <gmock/gmock.h>
2392+#include <gtest/gtest.h>
2393+
2394+#include <unistd.h>
2395+#include <memory>
2396+
2397+namespace mclia = mir::client::input::android;
2398+
2399+namespace droidinput = android;
2400+
2401+namespace
2402+{
2403+
2404+class TestingInputProducer
2405+{
2406+public:
2407+ TestingInputProducer(droidinput::sp<droidinput::InputChannel> input_channel) :
2408+ input_publisher(std::make_shared<droidinput::InputPublisher>(input_channel)),
2409+ incrementing_seq_id(1), // Sequence id must be > 0 or publisher will reject
2410+ testing_key_event_key_code(13)
2411+ {
2412+ }
2413+
2414+ // The input publisher does not care about event semantics so we only highlight
2415+ // a few fields for transport verification
2416+ void produce_a_key_event()
2417+ {
2418+ input_publisher->publishKeyEvent(
2419+ incrementing_seq_id,
2420+ filler_device_id,
2421+ 0 /* source */,
2422+ 0 /* action */,
2423+ 0 /* flags */,
2424+ testing_key_event_key_code,
2425+ 0 /* scan_code */,
2426+ 0 /* meta_state */,
2427+ 0 /* repeat_count */,
2428+ 0 /* down_time */,
2429+ 0 /* event_time */);
2430+ }
2431+ void produce_a_motion_event()
2432+ {
2433+ droidinput::PointerProperties filler_pointer_properties;
2434+ droidinput::PointerCoords filler_pointer_coordinates;
2435+
2436+ memset(&filler_pointer_properties, 0, sizeof(droidinput::PointerProperties));
2437+ memset(&filler_pointer_coordinates, 0, sizeof(droidinput::PointerCoords));
2438+
2439+ input_publisher->publishMotionEvent(
2440+ incrementing_seq_id,
2441+ filler_device_id,
2442+ 0 /* source */,
2443+ motion_event_action_flags,
2444+ 0 /* flags */,
2445+ 0 /* edge_flags */,
2446+ 0 /* meta_state */,
2447+ 0 /* button_state */,
2448+ 0 /* x_offset */, 0 /* y_offset */,
2449+ 0 /* x_precision */, 0 /* y_precision */,
2450+ 0 /* down_time */,
2451+ 0 /* event_time */,
2452+ default_pointer_count,
2453+ &filler_pointer_properties,
2454+ &filler_pointer_coordinates);
2455+ }
2456+
2457+ bool must_receive_handled_signal()
2458+ {
2459+ uint32_t seq;
2460+ bool handled;
2461+
2462+ auto status = input_publisher->receiveFinishedSignal(&seq, &handled);
2463+ return (status == droidinput::OK) && handled;
2464+ }
2465+
2466+ std::shared_ptr<droidinput::InputPublisher> input_publisher;
2467+
2468+ int incrementing_seq_id;
2469+ int32_t testing_key_event_key_code;
2470+
2471+ // Some default values
2472+ // device_id must be > 0 or input publisher will reject
2473+ static const int32_t filler_device_id = 1;
2474+ // AMOTION_EVENT_ACTION_MOVE is necessary to engage batching behavior
2475+ static const int32_t motion_event_action_flags = AMOTION_EVENT_ACTION_MOVE;
2476+ // We have to have at least 1 pointer or the publisher will fail to marshal a motion event
2477+ static const int32_t default_pointer_count = 1;
2478+};
2479+
2480+class AndroidInputReceiverSetup : public testing::Test
2481+{
2482+public:
2483+ AndroidInputReceiverSetup()
2484+ {
2485+ droidinput::String8 const testing_channel_name = droidinput::String8("Terrapin");
2486+ auto status = droidinput::InputChannel::openInputChannelPair(testing_channel_name,
2487+ android_client_channel,
2488+ android_server_channel);
2489+
2490+ EXPECT_EQ(droidinput::OK, status);
2491+ }
2492+
2493+ void flush_channels()
2494+ {
2495+ fsync(android_server_channel->getFd());
2496+ fsync(android_client_channel->getFd());
2497+ }
2498+
2499+ droidinput::sp<droidinput::InputChannel> android_client_channel;
2500+ droidinput::sp<droidinput::InputChannel> android_server_channel;
2501+
2502+ static std::chrono::milliseconds const next_event_timeout;
2503+};
2504+
2505+std::chrono::milliseconds const AndroidInputReceiverSetup::next_event_timeout(1000);
2506+
2507+}
2508+
2509+TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd)
2510+{
2511+ mclia::InputReceiver receiver(android_client_channel);
2512+
2513+ EXPECT_EQ(android_client_channel->getFd(), receiver.fd());
2514+}
2515+
2516+TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events)
2517+{
2518+ mclia::InputReceiver receiver(android_client_channel);
2519+ TestingInputProducer producer(android_server_channel);
2520+
2521+ producer.produce_a_key_event();
2522+
2523+ flush_channels();
2524+
2525+ MirEvent ev;
2526+ EXPECT_EQ(true, receiver.next_event(next_event_timeout, ev));
2527+ EXPECT_EQ(MIR_INPUT_EVENT_TYPE_KEY, ev.type);
2528+ EXPECT_EQ(producer.testing_key_event_key_code, ev.details.key.key_code);
2529+}
2530+
2531+TEST_F(AndroidInputReceiverSetup, receiver_handles_events)
2532+{
2533+ mclia::InputReceiver receiver(android_client_channel);
2534+ TestingInputProducer producer(android_server_channel);
2535+
2536+ producer.produce_a_key_event();
2537+ flush_channels();
2538+
2539+ MirEvent ev;
2540+ EXPECT_EQ(true, receiver.next_event(next_event_timeout, ev));
2541+
2542+ flush_channels();
2543+
2544+ EXPECT_TRUE (producer.must_receive_handled_signal());
2545+}
2546+
2547+TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events)
2548+{
2549+ mclia::InputReceiver receiver(android_client_channel);
2550+ TestingInputProducer producer(android_server_channel);
2551+
2552+ // Produce 3 motion events before client handles any.
2553+ producer.produce_a_motion_event();
2554+ producer.produce_a_motion_event();
2555+ producer.produce_a_motion_event();
2556+
2557+ flush_channels();
2558+
2559+ MirEvent ev;
2560+ // Handle all three events as a batched event
2561+ EXPECT_TRUE(receiver.next_event(next_event_timeout, ev));
2562+ // Now there should be no events
2563+ EXPECT_FALSE(receiver.next_event(std::chrono::milliseconds(1), ev)); // Minimal timeout needed for valgrind
2564+}
2565+
2566
2567=== added file 'tests/unit-tests/client/input/test_android_input_receiver_thread.cpp'
2568--- tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 1970-01-01 00:00:00 +0000
2569+++ tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2013-04-03 18:49:21 +0000
2570@@ -0,0 +1,152 @@
2571+/*
2572+ * Copyright © 2013 Canonical Ltd.
2573+ *
2574+ * This program is free software: you can redistribute it and/or modify it
2575+ * under the terms of the GNU Lesser General Public License version 3,
2576+ * as published by the Free Software Foundation.
2577+ *
2578+ * This program is distributed in the hope that it will be useful,
2579+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2580+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2581+ * GNU General Public License for more details.
2582+ *
2583+ * You should have received a copy of the GNU Lesser General Public License
2584+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2585+ *
2586+ * Authored by: Robert Carr <robert.carr@canonical.com>
2587+ */
2588+
2589+#include "src/client/input/android_input_receiver_thread.h"
2590+#include "src/client/input/android_input_receiver.h"
2591+
2592+#include "mir_toolkit/mir_client_library.h"
2593+
2594+#include <gtest/gtest.h>
2595+#include <gmock/gmock.h>
2596+
2597+#include <androidfw/InputTransport.h>
2598+
2599+#include <atomic>
2600+
2601+#include <fcntl.h>
2602+
2603+namespace mclia = mir::client::input::android;
2604+
2605+namespace
2606+{
2607+
2608+struct MockEventHandler
2609+{
2610+ MOCK_METHOD1(handle_event, void(MirEvent*));
2611+};
2612+
2613+struct MockInputReceiver : public mclia::InputReceiver
2614+{
2615+ MockInputReceiver(int fd)
2616+ : InputReceiver(fd)
2617+ {
2618+ }
2619+ MOCK_METHOD1(next_event, bool(MirEvent &));
2620+};
2621+
2622+struct AndroidInputReceiverThreadSetup : public testing::Test
2623+{
2624+ AndroidInputReceiverThreadSetup()
2625+ {
2626+ test_receiver_fd = open("/dev/null", O_APPEND);
2627+ input_receiver = std::make_shared<MockInputReceiver>(test_receiver_fd);
2628+ }
2629+ virtual ~AndroidInputReceiverThreadSetup()
2630+ {
2631+ close(test_receiver_fd);
2632+ }
2633+
2634+ int test_receiver_fd;
2635+ std::shared_ptr<MockInputReceiver> input_receiver;
2636+};
2637+
2638+ACTION_P(StopThread, thread)
2639+{
2640+ thread->stop();
2641+// thread->join();
2642+}
2643+
2644+}
2645+
2646+TEST_F(AndroidInputReceiverThreadSetup, reads_events_until_stopped)
2647+{
2648+ using namespace ::testing;
2649+
2650+ mclia::InputReceiverThread input_thread(input_receiver,
2651+ std::function<void(MirEvent*)>());
2652+ {
2653+ InSequence seq;
2654+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false));
2655+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false));
2656+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(false)));
2657+ }
2658+ input_thread.start();
2659+ input_thread.join();
2660+}
2661+
2662+TEST_F(AndroidInputReceiverThreadSetup, receives_and_dispatches_available_events_when_ready)
2663+{
2664+ using namespace ::testing;
2665+ MockEventHandler mock_handler;
2666+
2667+ struct InputDelegate
2668+ {
2669+ InputDelegate(MockEventHandler& handler)
2670+ : handler(handler) {}
2671+ void operator()(MirEvent* ev)
2672+ {
2673+ handler.handle_event(ev);
2674+ }
2675+ MockEventHandler &handler;
2676+ } input_delegate(mock_handler);
2677+
2678+ mclia::InputReceiverThread input_thread(input_receiver, input_delegate);
2679+ {
2680+ InSequence seq;
2681+
2682+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(true));
2683+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false));
2684+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(true)));
2685+ }
2686+ EXPECT_CALL(mock_handler, handle_event(_)).Times(2);
2687+
2688+ input_thread.start();
2689+ input_thread.join();
2690+}
2691+
2692+TEST_F(AndroidInputReceiverThreadSetup, input_callback_invoked_from_thread)
2693+{
2694+ using namespace ::testing;
2695+ MockEventHandler mock_handler;
2696+ std::atomic<bool> handled;
2697+
2698+ handled = false;
2699+
2700+ struct InputDelegate
2701+ {
2702+ InputDelegate(std::atomic<bool> &handled)
2703+ : handled(handled) {}
2704+ void operator()(MirEvent* /*ev*/)
2705+ {
2706+ handled = true;
2707+ }
2708+ std::atomic<bool> &handled;
2709+ } input_delegate(handled);
2710+
2711+ mclia::InputReceiverThread input_thread(input_receiver, input_delegate);
2712+ {
2713+ InSequence seq;
2714+
2715+ EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(true)));
2716+ }
2717+
2718+ input_thread.start();
2719+ while (handled == false) { } // We would block forever here were delivery not threaded
2720+ input_thread.join();
2721+}
2722+
2723
2724=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
2725--- tests/unit-tests/client/test_client_mir_surface.cpp 2013-03-26 09:37:47 +0000
2726+++ tests/unit-tests/client/test_client_mir_surface.cpp 2013-04-03 18:49:21 +0000
2727@@ -20,25 +20,30 @@
2728 #include "mir_toolkit/mir_client_library.h"
2729 #include "src/client/mir_logger.h"
2730 #include "src/client/client_buffer.h"
2731-#include "src/client/client_buffer_depository.h"
2732 #include "src/client/client_buffer_factory.h"
2733 #include "src/client/client_platform.h"
2734 #include "src/client/client_platform_factory.h"
2735 #include "src/client/mir_surface.h"
2736 #include "src/client/mir_connection.h"
2737+#include "src/client/input/input_platform.h"
2738+#include "src/client/input/input_receiver_thread.h"
2739 #include "mir/frontend/resource_cache.h"
2740
2741 #include "mir_test/test_protobuf_server.h"
2742 #include "mir_test/stub_server_tool.h"
2743 #include "mir_test/test_protobuf_client.h"
2744 #include "mir_test/gmock_fixes.h"
2745+#include "mir_test/fake_shared.h"
2746
2747 #include <cstring>
2748
2749 #include <gtest/gtest.h>
2750 #include <gmock/gmock.h>
2751
2752+#include <fcntl.h>
2753+
2754 namespace mcl = mir::client;
2755+namespace mcli = mcl::input;
2756 namespace mp = mir::protobuf;
2757 namespace geom = mir::geometry;
2758
2759@@ -52,10 +57,17 @@
2760 MockServerPackageGenerator()
2761 : global_buffer_id(0)
2762 {
2763- generate_unique_buffer();
2764 width_sent = 891;
2765 height_sent = 458;
2766 pf_sent = mir_pixel_format_abgr_8888;
2767+
2768+ input_fd = open("/dev/null", O_APPEND);
2769+ }
2770+ ~MockServerPackageGenerator()
2771+ {
2772+ close(input_fd);
2773+ for (int i = 0; i < server_package.fd_items; i++)
2774+ close(server_package.fd[0]);
2775 }
2776
2777 void create_surface(google::protobuf::RpcController*,
2778@@ -86,8 +98,12 @@
2779 int num_fd = 2, num_data = 8;
2780 for (auto i=0; i<num_fd; i++)
2781 {
2782- server_package.fd[i] = global_buffer_id * i;
2783+ if (server_package.fd[i])
2784+ close(server_package.fd[i]);
2785+ server_package.fd[i] = open("/dev/null", O_APPEND);
2786 }
2787+ server_package.fd_items = num_fd;
2788+ server_package.data_items = num_data;
2789 for (auto i=0; i<num_data; i++)
2790 {
2791 server_package.data[i] = (global_buffer_id + i) * 2;
2792@@ -100,16 +116,20 @@
2793 int width_sent;
2794 int height_sent;
2795 int pf_sent;
2796+
2797+ int input_fd;
2798
2799 private:
2800 int global_buffer_id;
2801
2802 void create_buffer_response(mir::protobuf::Buffer* response)
2803 {
2804+ generate_unique_buffer();
2805+
2806 response->set_buffer_id(global_buffer_id);
2807
2808 /* assemble buffers */
2809- response->set_fds_on_side_channel(1);
2810+ response->set_fds_on_side_channel(server_package.fd_items);
2811 for (int i=0; i< server_package.data_items; i++)
2812 {
2813 response->add_data(server_package.data[i]);
2814@@ -120,16 +140,18 @@
2815 }
2816
2817 response->set_stride(server_package.stride);
2818-
2819- generate_unique_buffer();
2820 }
2821
2822 void create_surface_response(mir::protobuf::Surface* response)
2823 {
2824+ response->set_fds_on_side_channel(1);
2825+
2826 response->mutable_id()->set_value(2);
2827 response->set_width(width_sent);
2828 response->set_height(height_sent);
2829 response->set_pixel_format(pf_sent);
2830+ response->add_fd(input_fd);
2831+
2832 create_buffer_response(response->mutable_buffer());
2833 }
2834 };
2835@@ -207,6 +229,26 @@
2836 }
2837 };
2838
2839+struct StubClientInputPlatform : public mcli::InputPlatform
2840+{
2841+ std::shared_ptr<mcli::InputReceiverThread> create_input_thread(int /* fd */, std::function<void(MirEvent*)> const& /* callback */)
2842+ {
2843+ return std::shared_ptr<mcli::InputReceiverThread>();
2844+ }
2845+};
2846+
2847+struct MockClientInputPlatform : public mcli::InputPlatform
2848+{
2849+ MOCK_METHOD2(create_input_thread, std::shared_ptr<mcli::InputReceiverThread>(int, std::function<void(MirEvent*)> const&));
2850+};
2851+
2852+struct MockInputReceiverThread : public mcli::InputReceiverThread
2853+{
2854+ MOCK_METHOD0(start, void());
2855+ MOCK_METHOD0(stop, void());
2856+ MOCK_METHOD0(join, void());
2857+};
2858+
2859 }
2860 }
2861
2862@@ -232,6 +274,8 @@
2863
2864 mock_buffer_factory = std::make_shared<mt::MockClientBufferFactory>();
2865
2866+ input_platform = std::make_shared<mt::StubClientInputPlatform>();
2867+
2868 params = MirSurfaceParameters{"test", 33, 45, mir_pixel_format_abgr_8888,
2869 mir_buffer_usage_hardware};
2870
2871@@ -261,6 +305,7 @@
2872
2873 MirSurfaceParameters params;
2874 std::shared_ptr<mt::MockClientBufferFactory> mock_buffer_factory;
2875+ std::shared_ptr<mt::StubClientInputPlatform> input_platform;
2876
2877 mir::protobuf::Connection response;
2878 mir::protobuf::ConnectParameters connect_parameters;
2879@@ -282,13 +327,7 @@
2880 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))
2881 .Times(1);
2882
2883- auto surface = std::make_shared<MirSurface> (connection.get(),
2884- *client_comm_channel,
2885- logger,
2886- mock_buffer_factory,
2887- params,
2888- &empty_callback,
2889- nullptr);
2890+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
2891
2892 auto wait_handle = surface->get_create_wait_handle();
2893 wait_handle->wait_for_result();
2894@@ -306,20 +345,14 @@
2895 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))
2896 .Times(1);
2897
2898- auto surface = std::make_shared<MirSurface> (connection.get(),
2899- *client_comm_channel,
2900- logger,
2901- mock_buffer_factory,
2902- params,
2903- &empty_callback,
2904- nullptr);
2905+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
2906
2907 auto wait_handle = surface->get_create_wait_handle();
2908 wait_handle->wait_for_result();
2909
2910 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))
2911 .Times(1);
2912- auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, (void*) NULL);
2913+ auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, nullptr);
2914 buffer_wait_handle->wait_for_result();
2915 }
2916
2917@@ -328,12 +361,11 @@
2918 // Can't simply use memcmp() on the whole struct because age is not sent over the wire
2919 if (package.data_items != arg.data_items)
2920 return false;
2921+ // Note we can not compare the fd's directly as they may change when being sent over the wire.
2922 if (package.fd_items != arg.fd_items)
2923 return false;
2924 if (memcmp(package.data, arg.data, sizeof(package.data[0]) * package.data_items))
2925 return false;
2926- if (memcmp(package.fd, arg.fd, sizeof(package.fd[0]) * package.fd_items))
2927- return false;
2928 if (package.stride != arg.stride)
2929 return false;
2930 return true;
2931@@ -349,13 +381,8 @@
2932 .WillOnce(DoAll(SaveArg<0>(&submitted_package),
2933 Return(mock_buffer_factory->emptybuffer)));
2934
2935- auto surface = std::make_shared<MirSurface> (connection.get(),
2936- *client_comm_channel,
2937- logger,
2938- mock_buffer_factory,
2939- params,
2940- &empty_callback,
2941- nullptr);
2942+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
2943+
2944 auto wait_handle = surface->get_create_wait_handle();
2945 wait_handle->wait_for_result();
2946
2947@@ -375,13 +402,8 @@
2948 .WillOnce(DoAll(SaveArg<1>(&sz),
2949 Return(mock_buffer_factory->emptybuffer)));
2950
2951- auto surface = std::make_shared<MirSurface> (connection.get(),
2952- *client_comm_channel,
2953- logger,
2954- mock_buffer_factory,
2955- params,
2956- &empty_callback,
2957- nullptr);
2958+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
2959+
2960 auto wait_handle = surface->get_create_wait_handle();
2961 wait_handle->wait_for_result();
2962
2963@@ -400,13 +422,8 @@
2964 .WillOnce(DoAll(SaveArg<1>(&sz),
2965 Return(mock_buffer_factory->emptybuffer)));
2966
2967- auto surface = std::make_shared<MirSurface> (connection.get(),
2968- *client_comm_channel,
2969- logger,
2970- mock_buffer_factory,
2971- params,
2972- &empty_callback,
2973- nullptr);
2974+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
2975+
2976 auto wait_handle = surface->get_create_wait_handle();
2977 wait_handle->wait_for_result();
2978
2979@@ -425,13 +442,7 @@
2980 .WillOnce(DoAll(SaveArg<2>(&pf),
2981 Return(mock_buffer_factory->emptybuffer)));
2982
2983- auto surface = std::make_shared<MirSurface> (connection.get(),
2984- *client_comm_channel,
2985- logger,
2986- mock_buffer_factory,
2987- params,
2988- &empty_callback,
2989- nullptr);
2990+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
2991
2992 auto wait_handle = surface->get_create_wait_handle();
2993 wait_handle->wait_for_result();
2994@@ -439,6 +450,46 @@
2995 EXPECT_EQ(pf, geom::PixelFormat::abgr_8888);
2996 }
2997
2998+
2999+
3000+namespace
3001+{
3002+static void null_event_callback(MirSurface*, MirEvent*, void*)
3003+{
3004+}
3005+}
3006+
3007+TEST_F(MirClientSurfaceTest, input_fd_used_to_create_input_thread_when_delegate_specified)
3008+{
3009+ using namespace ::testing;
3010+
3011+ auto mock_input_platform = std::make_shared<mt::MockClientInputPlatform>();
3012+ auto mock_input_thread = std::make_shared<mt::MockInputReceiverThread>();
3013+ MirEventDelegate delegate = {null_event_callback, nullptr};
3014+
3015+ EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)).Times(2);
3016+
3017+ EXPECT_CALL(*mock_input_platform, create_input_thread(_, _)).Times(1)
3018+ .WillOnce(Return(mock_input_thread));
3019+ EXPECT_CALL(*mock_input_thread, start()).Times(1);
3020+ EXPECT_CALL(*mock_input_thread, stop()).Times(1);
3021+
3022+ {
3023+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger,
3024+ mock_buffer_factory, mock_input_platform, params, &delegate, &empty_callback, nullptr);
3025+ auto wait_handle = surface->get_create_wait_handle();
3026+ wait_handle->wait_for_result();
3027+ }
3028+
3029+ {
3030+ // This surface should not trigger a call to the input platform as no input delegate is specified.
3031+ auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger,
3032+ mock_buffer_factory, mock_input_platform, params, nullptr, &empty_callback, nullptr);
3033+ auto wait_handle = surface->get_create_wait_handle();
3034+ wait_handle->wait_for_result();
3035+ }
3036+}
3037+
3038 TEST_F(MirClientSurfaceTest, get_buffer_returns_last_received_buffer_package)
3039 {
3040 using namespace testing;
3041@@ -450,7 +501,9 @@
3042 *client_comm_channel,
3043 logger,
3044 mock_buffer_factory,
3045+ input_platform,
3046 params,
3047+ nullptr,
3048 &empty_callback,
3049 nullptr);
3050 auto wait_handle = surface->get_create_wait_handle();
3051@@ -478,7 +531,9 @@
3052 *client_comm_channel,
3053 logger,
3054 mock_buffer_factory,
3055+ input_platform,
3056 params,
3057+ nullptr,
3058 &empty_callback,
3059 nullptr);
3060 surface->get_create_wait_handle()->wait_for_result();
3061
3062=== modified file 'tests/unit-tests/input/android/test_android_input_application_handle.cpp'
3063--- tests/unit-tests/input/android/test_android_input_application_handle.cpp 2013-03-29 16:51:35 +0000
3064+++ tests/unit-tests/input/android/test_android_input_application_handle.cpp 2013-04-03 18:49:21 +0000
3065@@ -20,8 +20,6 @@
3066
3067 #include "mir/input/session_target.h"
3068
3069-#include "mir_test/fake_shared.h"
3070-
3071 #include <gtest/gtest.h>
3072 #include <gmock/gmock.h>
3073
3074@@ -29,7 +27,6 @@
3075
3076 namespace mi = mir::input;
3077 namespace mia = mi::android;
3078-namespace mt = mir::test;
3079
3080 namespace
3081 {
3082@@ -44,15 +41,30 @@
3083 {
3084 using namespace ::testing;
3085 std::string const testing_session_name = "Cats";
3086- MockSessionHandle session;
3087+ auto session = std::make_shared<MockSessionHandle>();
3088
3089- EXPECT_CALL(session, name()).Times(AtLeast(1))
3090+ EXPECT_CALL(*session, name()).Times(AtLeast(1))
3091 .WillRepeatedly(Return(testing_session_name));
3092- mia::InputApplicationHandle application_handle(mt::fake_shared(session));
3093+ mia::InputApplicationHandle application_handle(session);
3094 EXPECT_TRUE(application_handle.updateInfo());
3095 auto info = application_handle.getInfo();
3096 EXPECT_EQ(INT_MAX, info->dispatchingTimeout);
3097 EXPECT_EQ(droidinput::String8(testing_session_name.c_str()), info->name);
3098 }
3099
3100+TEST(AndroidInputApplicationHandle, does_not_own_session)
3101+{
3102+ using namespace ::testing;
3103+ std::string const testing_session_name = "Let it Grow";
3104+
3105+ auto session = std::make_shared<MockSessionHandle>();
3106+ EXPECT_CALL(*session, name()).Times(AtLeast(1))
3107+ .WillRepeatedly(Return(testing_session_name));
3108+
3109+ mia::InputApplicationHandle application_handle(session);
3110+ EXPECT_TRUE(application_handle.updateInfo());
3111+ session.reset();
3112+ EXPECT_FALSE(application_handle.updateInfo());
3113+
3114+}
3115
3116
3117=== modified file 'tests/unit-tests/input/android/test_android_input_lexicon.cpp'
3118--- tests/unit-tests/input/android/test_android_input_lexicon.cpp 2013-03-13 08:09:52 +0000
3119+++ tests/unit-tests/input/android/test_android_input_lexicon.cpp 2013-04-03 18:49:21 +0000
3120@@ -15,8 +15,8 @@
3121 *
3122 * Authored by: Robert Carr <robert.carr@canonical.com>
3123 */
3124-#include "src/server/input/android/android_input_lexicon.h"
3125-// Is this the right place for this header? Will eventually be included by clients.
3126+
3127+#include "mir/input/android/android_input_lexicon.h"
3128 #include "mir_toolkit/input/event.h"
3129
3130 #include <androidfw/Input.h>
3131@@ -25,7 +25,7 @@
3132 #include <gmock/gmock.h>
3133
3134 namespace mi = mir::input;
3135-namespace mia = mir::input::android;
3136+namespace miat = mir::input::android::transport;
3137
3138 TEST(AndroidInputLexicon, translates_key_events)
3139 {
3140@@ -48,7 +48,7 @@
3141 down_time, event_time);
3142
3143 MirEvent mir_ev;
3144- mia::Lexicon::translate(android_key_ev, mir_ev);
3145+ miat::Lexicon::translate(android_key_ev, mir_ev);
3146
3147 // Common event properties
3148 EXPECT_EQ(device_id, mir_ev.device_id);
3149@@ -121,7 +121,7 @@
3150 event_time, pointer_count, &pointer_properties, &pointer_coords);
3151
3152 MirEvent mir_ev;
3153- mia::Lexicon::translate(android_motion_ev, mir_ev);
3154+ miat::Lexicon::translate(android_motion_ev, mir_ev);
3155
3156 // Common event properties
3157 EXPECT_EQ(device_id, mir_ev.device_id);
3158
3159=== modified file 'tests/unit-tests/input/android/test_android_input_window_handle.cpp'
3160--- tests/unit-tests/input/android/test_android_input_window_handle.cpp 2013-03-29 16:51:35 +0000
3161+++ tests/unit-tests/input/android/test_android_input_window_handle.cpp 2013-04-03 18:49:21 +0000
3162@@ -80,7 +80,7 @@
3163
3164 auto info = handle.getInfo();
3165
3166- EXPECT_EQ(testing_surface_name, info->name);
3167+ EXPECT_EQ(droidinput::String8(testing_surface_name.c_str()), info->name);
3168
3169 EXPECT_EQ(testing_server_fd, info->inputChannel->getFd());
3170

Subscribers

People subscribed via source and target branches