Mir

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

Proposed by Robert Carr
Status: Merged
Approved by: Thomas Voß
Approved revision: no longer in the source branch.
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
3rd_party/CMakeLists.txt (+2/-6)
3rd_party/android-deps/std/SortedVector.h (+1/-1)
3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h (+2/-0)
3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp (+5/-0)
CMakeLists.txt (+0/-7)
cross-compile-chroot.sh (+0/-1)
debian/rules (+0/-1)
doc/building_source_for_android.md (+2/-2)
examples/demo_client.c (+1/-1)
examples/demo_client_accelerated.cpp (+1/-1)
examples/demo_client_unaccelerated.c (+1/-1)
examples/eglapp.c (+14/-1)
examples/render_surfaces.cpp (+2/-16)
include/client/mir_toolkit/mir_client_library.h (+3/-1)
include/server/mir/input/null_input_manager.h (+56/-0)
include/shared/mir/input/android/android_input_lexicon.h (+7/-0)
include/shared/mir_toolkit/c_types.h (+21/-0)
include/shared/mir_toolkit/input/event.h (+2/-2)
include/test/mir_test/wait_condition.h (+5/-3)
src/client/CMakeLists.txt (+10/-3)
src/client/input/CMakeLists.txt (+12/-0)
src/client/input/android_input_platform.cpp (+44/-0)
src/client/input/android_input_platform.h (+52/-0)
src/client/input/android_input_receiver.cpp (+91/-0)
src/client/input/android_input_receiver.h (+84/-0)
src/client/input/android_input_receiver_thread.cpp (+68/-0)
src/client/input/android_input_receiver_thread.h (+71/-0)
src/client/input/input_platform.h (+55/-0)
src/client/input/input_receiver_thread.h (+48/-0)
src/client/mir_client_library.cpp (+10/-6)
src/client/mir_client_surface.h (+1/-0)
src/client/mir_connection.cpp (+8/-2)
src/client/mir_connection.h (+7/-0)
src/client/mir_surface.cpp (+19/-1)
src/client/mir_surface.h (+13/-0)
src/server/CMakeLists.txt (+1/-0)
src/server/default_server_configuration.cpp (+7/-2)
src/server/frontend/protobuf_message_processor.cpp (+4/-2)
src/server/input/CMakeLists.txt (+0/-7)
src/server/input/android/CMakeLists.txt (+1/-1)
src/server/input/android/android_input_application_handle.cpp (+6/-1)
src/server/input/android/android_input_application_handle.h (+1/-1)
src/server/input/android/event_filter_dispatcher_policy.cpp (+3/-2)
src/server/input/android/transport/CMakeLists.txt (+31/-0)
src/server/input/android/transport/android_input_lexicon.cpp (+7/-7)
src/server/input/dummy_input_manager.cpp (+0/-42)
tests/acceptance-tests/CMakeLists.txt (+4/-0)
tests/acceptance-tests/test_client_input.cpp (+268/-0)
tests/acceptance-tests/test_client_library.cpp (+7/-7)
tests/acceptance-tests/test_focus_management_api.cpp (+1/-1)
tests/acceptance-tests/test_focus_selection.cpp (+1/-1)
tests/acceptance-tests/test_surfaceloop.cpp (+5/-5)
tests/integration-tests/CMakeLists.txt (+0/-2)
tests/integration-tests/client/test_client_render.cpp (+8/-8)
tests/integration-tests/input/android/test_android_cursor_listener.cpp (+2/-3)
tests/integration-tests/input/android/test_android_input_manager.cpp (+8/-9)
tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp (+2/-3)
tests/integration-tests/test_error_reporting.cpp (+1/-1)
tests/integration-tests/test_surfaceloop.cpp (+4/-4)
tests/mir_test_doubles/CMakeLists.txt (+0/-2)
tests/unit-tests/CMakeLists.txt (+0/-3)
tests/unit-tests/client/CMakeLists.txt (+4/-0)
tests/unit-tests/client/input/CMakeLists.txt (+9/-0)
tests/unit-tests/client/input/test_android_input_receiver.cpp (+198/-0)
tests/unit-tests/client/input/test_android_input_receiver_thread.cpp (+152/-0)
tests/unit-tests/client/test_client_mir_surface.cpp (+106/-51)
tests/unit-tests/input/android/test_android_input_application_handle.cpp (+18/-6)
tests/unit-tests/input/android/test_android_input_lexicon.cpp (+5/-5)
tests/unit-tests/input/android/test_android_input_window_handle.cpp (+1/-1)
To merge this branch: bzr merge lp:~robertcarr/mir/receive-input-in-client
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Approve
Chris Halse Rogers Approve
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.
Revision history for this message
Robert Carr (robertcarr) wrote :

Jenkins will fail due to MIR_INPUT_USE_ANDROID_TYPES=false

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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
Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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
Revision history for this message
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...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Spurious whitespace:

1302 -
1303 +

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Probably OK once the conflict is fixed

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

1236 -
1237 +

Spurious whitespace

Revision history for this message
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
Revision history for this message
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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

Many whitespace and style fixes

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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
Revision history for this message
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))"?

Revision history for this message
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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '3rd_party/CMakeLists.txt'
--- 3rd_party/CMakeLists.txt 2013-03-21 03:32:59 +0000
+++ 3rd_party/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -28,10 +28,8 @@
28 add_subdirectory(android-fbtype)28 add_subdirectory(android-fbtype)
29endif()29endif()
3030
31if (NOT MIR_DISABLE_INPUT)31include_directories(${CMAKE_CURRENT_SOURCE_DIR}/android-deps)
32 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/android-deps)32add_subdirectory(android-input)
33 add_subdirectory(android-input)
34endif()
3533
36set(MIR_ANDROID_INCLUDE_DIRECTORIES ${MIR_ANDROID_INCLUDE_DIRECTORIES} PARENT_SCOPE)34set(MIR_ANDROID_INCLUDE_DIRECTORIES ${MIR_ANDROID_INCLUDE_DIRECTORIES} PARENT_SCOPE)
37set(35set(
@@ -39,9 +37,7 @@
39 ${MIR_ANDROID_INPUT_COMPILE_FLAGS}37 ${MIR_ANDROID_INPUT_COMPILE_FLAGS}
40 PARENT_SCOPE)38 PARENT_SCOPE)
41 39
42if (NOT MIR_DISABLE_INPUT)
43target_link_libraries(40target_link_libraries(
44 3rd_party41 3rd_party
4542
46 android-input)43 android-input)
47endif()
4844
=== modified file '3rd_party/android-deps/std/SortedVector.h'
--- 3rd_party/android-deps/std/SortedVector.h 2013-03-13 04:54:15 +0000
+++ 3rd_party/android-deps/std/SortedVector.h 2013-04-03 18:49:21 +0000
@@ -133,7 +133,7 @@
133 ssize_t remove(const ValueType& item)133 ssize_t remove(const ValueType& item)
134 {134 {
135 auto remove_pos = lower_bound(begin(), end(), item);135 auto remove_pos = lower_bound(begin(), end(), item);
136 if (*remove_pos == item)136 if (remove_pos != end() && *remove_pos == item)
137 {137 {
138 auto removed_at = erase(remove_pos);138 auto removed_at = erase(remove_pos);
139 return distance(begin(), removed_at);139 return distance(begin(), removed_at);
140140
=== modified file '3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h'
--- 3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h 2013-03-13 04:54:15 +0000
+++ 3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.h 2013-04-03 18:49:21 +0000
@@ -43,6 +43,8 @@
43 * Intermediate representation used to send input events and related signals.43 * Intermediate representation used to send input events and related signals.
44 */44 */
45struct InputMessage {45struct InputMessage {
46 InputMessage();
47
46 enum {48 enum {
47 TYPE_KEY = 1,49 TYPE_KEY = 1,
48 TYPE_MOTION = 2,50 TYPE_MOTION = 2,
4951
=== modified file '3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp'
--- 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp 2013-02-11 11:51:22 +0000
+++ 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp 2013-04-03 18:49:21 +0000
@@ -63,6 +63,11 @@
6363
64// --- InputMessage ---64// --- InputMessage ---
6565
66InputMessage::InputMessage()
67{
68 memset(this, 0, sizeof(InputMessage));
69}
70
66bool InputMessage::isValid(size_t actualSize) const {71bool InputMessage::isValid(size_t actualSize) const {
67 if (size() == actualSize) {72 if (size() == actualSize) {
68 switch (header.type) {73 switch (header.type) {
6974
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2013-03-28 14:20:06 +0000
+++ CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -103,13 +103,6 @@
103 "graphics backend to build (options are 'gbm' or 'android')"103 "graphics backend to build (options are 'gbm' or 'android')"
104)104)
105105
106set (MIR_DISABLE_INPUT
107 false
108 CACHE
109 BOOL
110 "Don't build the input subsystem"
111)
112
113set (MIR_INPUT_USE_ANDROID_TYPES106set (MIR_INPUT_USE_ANDROID_TYPES
114 false107 false
115 CACHE108 CACHE
116109
=== modified file 'cross-compile-chroot.sh'
--- cross-compile-chroot.sh 2013-03-26 15:55:51 +0000
+++ cross-compile-chroot.sh 2013-04-03 18:49:21 +0000
@@ -26,7 +26,6 @@
26 -DBoost_COMPILER=-gcc \26 -DBoost_COMPILER=-gcc \
27 -DMIR_ENABLE_DEATH_TESTS=NO \27 -DMIR_ENABLE_DEATH_TESTS=NO \
28 -DMIR_PLATFORM=android \28 -DMIR_PLATFORM=android \
29 -DMIR_DISABLE_INPUT=true \
30 .. 29 ..
3130
32 cmake --build .31 cmake --build .
3332
=== modified file 'debian/rules'
--- debian/rules 2013-03-13 04:54:15 +0000
+++ debian/rules 2013-04-03 18:49:21 +0000
@@ -15,7 +15,6 @@
1515
16COMMON_CONFIGURE_OPTIONS = \16COMMON_CONFIGURE_OPTIONS = \
17 -DMIR_DISABLE_EPOLL_REACTOR=YES \17 -DMIR_DISABLE_EPOLL_REACTOR=YES \
18 -DMIR_DISABLE_INPUT=YES \
19 -DBUILD_DOXYGEN=YES18 -DBUILD_DOXYGEN=YES
2019
21# We need to rely on the select-based reactor to fix the ppa builds.20# We need to rely on the select-based reactor to fix the ppa builds.
2221
=== modified file 'doc/building_source_for_android.md'
--- doc/building_source_for_android.md 2013-03-26 16:30:53 +0000
+++ doc/building_source_for_android.md 2013-04-03 18:49:21 +0000
@@ -42,7 +42,7 @@
4242
43 $ bzr branch lp:mir43 $ bzr branch lp:mir
44 $ mkdir mir/build; cd mir/build44 $ mkdir mir/build; cd mir/build
45 $ cmake -DBoost_COMPILER=-gcc -DMIR_ENABLE_DEATH_TESTS=NO -DMIR_PLATFORM=android -DMIR_DISABLE_INPUT=yes ..45 $ cmake -DBoost_COMPILER=-gcc -DMIR_ENABLE_DEATH_TESTS=NO -DMIR_PLATFORM=android ..
4646
47Cross Compile47Cross Compile
48-------------48-------------
@@ -63,7 +63,7 @@
6363
64 $ bzr branch lp:mir64 $ bzr branch lp:mir
65 $ mkdir mir/build; cd mir/build65 $ mkdir mir/build; cd mir/build
66 $ 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 ..66 $ 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 ..
67 $ make67 $ make
6868
69N.B. The `cross-compile-android.sh` script in mir's top level directory69N.B. The `cross-compile-android.sh` script in mir's top level directory
7070
=== modified file 'examples/demo_client.c'
--- examples/demo_client.c 2013-03-22 10:34:16 +0000
+++ examples/demo_client.c 2013-04-03 18:49:21 +0000
@@ -129,7 +129,7 @@
129 /// \snippet demo_client.c surface_create_tag129 /// \snippet demo_client.c surface_create_tag
130 ///\internal [surface_create_tag]130 ///\internal [surface_create_tag]
131 // ...we create a surface using that format and wait for callback to complete.131 // ...we create a surface using that format and wait for callback to complete.
132 mir_wait_for(mir_surface_create(mcd.connection, &request_params, surface_create_callback, &mcd));132 mir_wait_for(mir_surface_create(mcd.connection, &request_params, NULL, surface_create_callback, &mcd));
133 puts("Surface created");133 puts("Surface created");
134 ///\internal [surface_create_tag]134 ///\internal [surface_create_tag]
135135
136136
=== modified file 'examples/demo_client_accelerated.cpp'
--- examples/demo_client_accelerated.cpp 2013-03-22 10:34:16 +0000
+++ examples/demo_client_accelerated.cpp 2013-04-03 18:49:21 +0000
@@ -72,7 +72,7 @@
72 MirSurfaceParameters const request_params =72 MirSurfaceParameters const request_params =
73 {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_hardware};73 {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_hardware};
7474
75 surface = mir_surface_create_sync(connection, &request_params);75 surface = mir_surface_create_sync(connection, &request_params, NULL);
76 assert(surface != NULL);76 assert(surface != NULL);
77 assert(mir_surface_is_valid(surface));77 assert(mir_surface_is_valid(surface));
78 assert(strcmp(mir_surface_get_error_message(surface), "") == 0);78 assert(strcmp(mir_surface_get_error_message(surface), "") == 0);
7979
=== modified file 'examples/demo_client_unaccelerated.c'
--- examples/demo_client_unaccelerated.c 2013-03-29 16:51:35 +0000
+++ examples/demo_client_unaccelerated.c 2013-04-03 18:49:21 +0000
@@ -132,7 +132,7 @@
132 MirSurfaceParameters const request_params =132 MirSurfaceParameters const request_params =
133 {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_software};133 {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_software};
134134
135 surface = mir_surface_create_sync(connection, &request_params);135 surface = mir_surface_create_sync(connection, &request_params, NULL);
136 assert(surface != NULL);136 assert(surface != NULL);
137 assert(mir_surface_is_valid(surface));137 assert(mir_surface_is_valid(surface));
138 assert(strcmp(mir_surface_get_error_message(surface), "") == 0);138 assert(strcmp(mir_surface_get_error_message(surface), "") == 0);
139139
=== modified file 'examples/eglapp.c'
--- examples/eglapp.c 2013-03-20 05:03:03 +0000
+++ examples/eglapp.c 2013-04-03 18:49:21 +0000
@@ -85,6 +85,14 @@
85 }85 }
86}86}
8787
88static void mir_eglapp_handle_input(MirSurface* surface, MirEvent* ev, void* context)
89{
90 (void) surface;
91 (void) context;
92 if (ev->details.key.key_code == 45) /* Q */
93 running = 0;
94}
95
88mir_eglapp_bool mir_eglapp_init(int *width, int *height)96mir_eglapp_bool mir_eglapp_init(int *width, int *height)
89{97{
90 EGLint attribs[] =98 EGLint attribs[] =
@@ -106,6 +114,11 @@
106 mir_pixel_format_xbgr_8888,114 mir_pixel_format_xbgr_8888,
107 mir_buffer_usage_hardware115 mir_buffer_usage_hardware
108 };116 };
117 MirEventDelegate delegate =
118 {
119 mir_eglapp_handle_input,
120 NULL
121 };
109 MirDisplayInfo dinfo;122 MirDisplayInfo dinfo;
110 MirSurface *surface;123 MirSurface *surface;
111 EGLConfig eglconfig;124 EGLConfig eglconfig;
@@ -127,7 +140,7 @@
127 surfaceparm.pixel_format = dinfo.supported_pixel_format[0];140 surfaceparm.pixel_format = dinfo.supported_pixel_format[0];
128 printf("Using pixel format #%d\n", surfaceparm.pixel_format);141 printf("Using pixel format #%d\n", surfaceparm.pixel_format);
129142
130 surface = mir_surface_create_sync(connection, &surfaceparm);143 surface = mir_surface_create_sync(connection, &surfaceparm, &delegate);
131 CHECK(mir_surface_is_valid(surface), "Can't create a surface");144 CHECK(mir_surface_is_valid(surface), "Can't create a surface");
132145
133 egldisplay = eglGetDisplay(146 egldisplay = eglGetDisplay(
134147
=== modified file 'examples/render_surfaces.cpp'
--- examples/render_surfaces.cpp 2013-04-02 09:36:09 +0000
+++ examples/render_surfaces.cpp 2013-04-03 18:49:21 +0000
@@ -23,7 +23,7 @@
23#include "mir/geometry/size.h"23#include "mir/geometry/size.h"
24#include "mir/graphics/buffer_initializer.h"24#include "mir/graphics/buffer_initializer.h"
25#include "mir/graphics/display.h"25#include "mir/graphics/display.h"
26#include "mir/input/input_manager.h"26#include "mir/input/null_input_manager.h"
27#include "mir/shell/surface_builder.h"27#include "mir/shell/surface_builder.h"
28#include "mir/surfaces/surface.h"28#include "mir/surfaces/surface.h"
29#include "mir/default_server_configuration.h"29#include "mir/default_server_configuration.h"
@@ -380,20 +380,6 @@
380// Stub out input.380// Stub out input.
381std::shared_ptr<mi::InputManager> RenderSurfacesServerConfiguration::the_input_manager()381std::shared_ptr<mi::InputManager> RenderSurfacesServerConfiguration::the_input_manager()
382{382{
383 struct NullInputManager : public mi::InputManager383 return std::make_shared<mi::NullInputManager>();
384 {
385 void start() {}
386 void stop() {}
387 std::shared_ptr<mi::InputChannel> make_input_channel()
388 {
389 return std::shared_ptr<mi::InputChannel>();
390 }
391 void set_input_focus_to(std::shared_ptr<mi::SessionTarget> const& /* session */,
392 std::shared_ptr<mi::SurfaceTarget> const& /* surface */)
393 {
394 }
395 };
396
397 return std::make_shared<NullInputManager>();
398}384}
399///\internal [NullInputManager_tag]385///\internal [NullInputManager_tag]
400386
=== modified file 'include/client/mir_toolkit/mir_client_library.h'
--- include/client/mir_toolkit/mir_client_library.h 2013-03-29 11:39:30 +0000
+++ include/client/mir_toolkit/mir_client_library.h 2013-04-03 18:49:21 +0000
@@ -124,6 +124,7 @@
124MirWaitHandle *mir_surface_create(124MirWaitHandle *mir_surface_create(
125 MirConnection *connection,125 MirConnection *connection,
126 MirSurfaceParameters const *surface_parameters,126 MirSurfaceParameters const *surface_parameters,
127 MirEventDelegate const *event_handler,
127 mir_surface_lifecycle_callback callback,128 mir_surface_lifecycle_callback callback,
128 void *context);129 void *context);
129130
@@ -135,7 +136,8 @@
135 * \return The resulting surface136 * \return The resulting surface
136 */137 */
137MirSurface *mir_surface_create_sync(MirConnection *connection,138MirSurface *mir_surface_create_sync(MirConnection *connection,
138 MirSurfaceParameters const *params);139 MirSurfaceParameters const *params,
140 MirEventDelegate const *event_handler);
139141
140/**142/**
141 * Get a window type that can be used for OpenGL ES 2.0 acceleration.143 * Get a window type that can be used for OpenGL ES 2.0 acceleration.
142144
=== added file 'include/server/mir/input/null_input_manager.h'
--- include/server/mir/input/null_input_manager.h 1970-01-01 00:00:00 +0000
+++ include/server/mir/input/null_input_manager.h 2013-04-03 18:49:21 +0000
@@ -0,0 +1,56 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_INPUT_NULL_INPUT_MANAGER_H_
20#define MIR_INPUT_NULL_INPUT_MANAGER_H_
21
22#include "mir/input/input_manager.h"
23
24namespace mir
25{
26namespace input
27{
28
29class NullInputManager : public InputManager
30{
31public:
32 NullInputManager() {};
33 virtual ~NullInputManager() {}
34
35 void start() {}
36 void stop() {}
37
38 std::shared_ptr<InputChannel> make_input_channel()
39 {
40 return std::shared_ptr<InputChannel>();
41 }
42
43 virtual void set_input_focus_to(std::shared_ptr<input::SessionTarget> const& /* session */,
44 std::shared_ptr<input::SurfaceTarget> const& /* surface */)
45 {
46 }
47
48protected:
49 NullInputManager(const NullInputManager&) = delete;
50 NullInputManager& operator=(const NullInputManager&) = delete;
51};
52
53}
54}
55
56#endif // MIR_INPUT_NULL_INPUT_MANAGER
057
=== added directory 'include/shared/mir/input'
=== added directory 'include/shared/mir/input/android'
=== renamed file 'src/server/input/android/android_input_lexicon.h' => 'include/shared/mir/input/android/android_input_lexicon.h'
--- src/server/input/android/android_input_lexicon.h 2013-03-13 04:54:15 +0000
+++ include/shared/mir/input/android/android_input_lexicon.h 2013-04-03 18:49:21 +0000
@@ -35,11 +35,18 @@
35{35{
36namespace android36namespace android
37{37{
38namespace transport
39{
40
41/// The Lexicon translates droidinput event types to MirEvent types prior to
42/// shell or client handling.
38class Lexicon43class Lexicon
39{44{
40public:45public:
41 static void translate(const droidinput::InputEvent *android_event, MirEvent &mir_event);46 static void translate(const droidinput::InputEvent *android_event, MirEvent &mir_event);
42};47};
48
49}
43}50}
44}51}
45}52}
4653
=== modified file 'include/shared/mir_toolkit/c_types.h'
--- include/shared/mir_toolkit/c_types.h 2013-03-29 11:27:00 +0000
+++ include/shared/mir_toolkit/c_types.h 2013-04-03 18:49:21 +0000
@@ -19,6 +19,8 @@
19#ifndef MIR_TOOLKIT_C_TYPES_H_19#ifndef MIR_TOOLKIT_C_TYPES_H_
20#define MIR_TOOLKIT_C_TYPES_H_20#define MIR_TOOLKIT_C_TYPES_H_
2121
22#include <mir_toolkit/input/event.h>
23
22#ifdef __cplusplus24#ifdef __cplusplus
23/**25/**
24 * \defgroup mir_toolkit MIR graphics tools API26 * \defgroup mir_toolkit MIR graphics tools API
@@ -60,6 +62,15 @@
60typedef void (*mir_surface_lifecycle_callback)(MirSurface *surface, void *client_context);62typedef void (*mir_surface_lifecycle_callback)(MirSurface *surface, void *client_context);
6163
62/**64/**
65 * Callback member of MirEventDelegate for handling of input events.
66 * \param [in] surface The surface on which an event has occurred
67 * \param [in] event The event to be handled
68 * \param [in,out] context The context provided by client during delegate
69 * registration.
70 */
71typedef void (*mir_event_delegate_handle_input_callback)(MirSurface* surface, MirEvent* ev, void* context);
72
73/**
63 * The order of components in a format enum matches the74 * The order of components in a format enum matches the
64 * order of the components as they would be written in an75 * order of the components as they would be written in an
65 * integer representing a pixel value of that format.76 * integer representing a pixel value of that format.
@@ -158,6 +169,16 @@
158 MirPixelFormat supported_pixel_format[mir_supported_pixel_format_max];169 MirPixelFormat supported_pixel_format[mir_supported_pixel_format_max];
159} MirDisplayInfo;170} MirDisplayInfo;
160171
172/**
173 * MirEventDelegate may be used to specify (at surface creation time) callbacks for
174 * handling of input events
175 */
176typedef struct MirEventDelegate
177{
178 mir_event_delegate_handle_input_callback handle_input;
179 void *context;
180} MirEventDelegate;
181
161#ifdef __cplusplus182#ifdef __cplusplus
162}183}
163/**@}*/184/**@}*/
164185
=== modified file 'include/shared/mir_toolkit/input/event.h'
--- include/shared/mir_toolkit/input/event.h 2013-03-29 11:39:30 +0000
+++ include/shared/mir_toolkit/input/event.h 2013-04-03 18:49:21 +0000
@@ -41,7 +41,7 @@
41 MIR_INPUT_EVENT_TYPE_HW_SWITCH41 MIR_INPUT_EVENT_TYPE_HW_SWITCH
42 } MirEventType;42 } MirEventType;
4343
44 struct MirEvent44 typedef struct MirEvent
45 {45 {
46 /* Generic event properties */46 /* Generic event properties */
47 MirEventType type;47 MirEventType type;
@@ -94,7 +94,7 @@
94 } pointer_coordinates[MIR_INPUT_EVENT_MAX_POINTER_COUNT];94 } pointer_coordinates[MIR_INPUT_EVENT_MAX_POINTER_COUNT];
95 } motion;95 } motion;
96 } details;96 } details;
97 };97 } MirEvent;
9898
99#ifdef __cplusplus99#ifdef __cplusplus
100}100}
101101
=== modified file 'include/test/mir_test/wait_condition.h'
--- include/test/mir_test/wait_condition.h 2013-03-22 16:41:59 +0000
+++ include/test/mir_test/wait_condition.h 2013-04-03 18:49:21 +0000
@@ -19,12 +19,16 @@
19#ifndef MIR_TEST_WAIT_CONDITION_H_19#ifndef MIR_TEST_WAIT_CONDITION_H_
20#define MIR_TEST_WAIT_CONDITION_H_20#define MIR_TEST_WAIT_CONDITION_H_
2121
22#include <gmock/gmock.h>
23
22#include <chrono>24#include <chrono>
23#include <mutex>25#include <mutex>
24#include <condition_variable>26#include <condition_variable>
2527
26namespace mir28namespace mir
27{29{
30namespace test
31{
28struct WaitCondition32struct WaitCondition
29{33{
30 WaitCondition() : woken(false) {}34 WaitCondition() : woken(false) {}
@@ -46,10 +50,7 @@
46 std::condition_variable condition;50 std::condition_variable condition;
47 bool woken;51 bool woken;
48};52};
49}
5053
51namespace
52{
53ACTION_P(ReturnFalseAndWakeUp, wait_condition)54ACTION_P(ReturnFalseAndWakeUp, wait_condition)
54{55{
55 wait_condition->wake_up_everyone();56 wait_condition->wake_up_everyone();
@@ -60,5 +61,6 @@
60 wait_condition->wake_up_everyone();61 wait_condition->wake_up_everyone();
61}62}
62}63}
64}
6365
64#endif // MIR_TEST_WAIT_CONDITION_H_66#endif // MIR_TEST_WAIT_CONDITION_H_
6567
=== modified file 'src/client/CMakeLists.txt'
--- src/client/CMakeLists.txt 2013-03-29 22:30:35 +0000
+++ src/client/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -35,6 +35,7 @@
35 mir_basic_rpc_channel.cpp35 mir_basic_rpc_channel.cpp
36 ${PROTO_SRCS}36 ${PROTO_SRCS}
37)37)
38add_subdirectory(input)
3839
39list(APPEND CLIENT_SOURCES40list(APPEND CLIENT_SOURCES
40 mir_socket_rpc_channel.cpp41 mir_socket_rpc_channel.cpp
@@ -82,15 +83,15 @@
82 SOVERSION ${MIR_VERSION_MAJOR}83 SOVERSION ${MIR_VERSION_MAJOR}
83)84)
8485
85target_link_libraries(86set(
86 mirclient87 MIR_CLIENT_LIBRARIES
87
88 ${Boost_LIBRARIES}88 ${Boost_LIBRARIES}
89 ${CMAKE_THREAD_LIBS_INIT}89 ${CMAKE_THREAD_LIBS_INIT}
90 ${LIBHARDWARE_LIBRARIES}90 ${LIBHARDWARE_LIBRARIES}
91 ${PROTOBUF_LIBRARIES}91 ${PROTOBUF_LIBRARIES}
9292
93 mirprotobuf93 mirprotobuf
94 mirinputandroidtransport
9495
95 ${DRM_LIBRARIES}96 ${DRM_LIBRARIES}
96 ${MIR_COMMON_PLATFORM_LIBRARIES}97 ${MIR_COMMON_PLATFORM_LIBRARIES}
@@ -98,6 +99,12 @@
98 3rd_party99 3rd_party
99)100)
100101
102target_link_libraries(
103 mirclient
104
105 ${MIR_CLIENT_LIBRARIES}
106)
107
101install(108install(
102 TARGETS mirclient109 TARGETS mirclient
103 LIBRARY DESTINATION lib110 LIBRARY DESTINATION lib
104111
=== added directory 'src/client/input'
=== added file 'src/client/input/CMakeLists.txt'
--- src/client/input/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/client/input/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -0,0 +1,12 @@
1list(
2 APPEND CLIENT_SOURCES
3 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_receiver.cpp
4 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_receiver_thread.cpp
5 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_platform.cpp
6)
7
8set(
9 CLIENT_SOURCES
10 ${CLIENT_SOURCES}
11 PARENT_SCOPE
12)
013
=== added file 'src/client/input/android_input_platform.cpp'
--- src/client/input/android_input_platform.cpp 1970-01-01 00:00:00 +0000
+++ src/client/input/android_input_platform.cpp 2013-04-03 18:49:21 +0000
@@ -0,0 +1,44 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "android_input_platform.h"
20#include "android_input_receiver.h"
21#include "android_input_receiver_thread.h"
22
23namespace mcli = mir::client::input;
24namespace mclia = mcli::android;
25
26mclia::AndroidInputPlatform::AndroidInputPlatform()
27{
28}
29
30mclia::AndroidInputPlatform::~AndroidInputPlatform()
31{
32}
33
34std::shared_ptr<mcli::InputReceiverThread> mclia::AndroidInputPlatform::create_input_thread(
35 int fd, std::function<void(MirEvent*)> const& callback)
36{
37 auto receiver = std::make_shared<mclia::InputReceiver>(fd);
38 return std::make_shared<mclia::InputReceiverThread>(receiver, callback);
39}
40
41std::shared_ptr<mcli::InputPlatform> mcli::InputPlatform::create()
42{
43 return std::make_shared<mclia::AndroidInputPlatform>();
44}
045
=== added file 'src/client/input/android_input_platform.h'
--- src/client/input/android_input_platform.h 1970-01-01 00:00:00 +0000
+++ src/client/input/android_input_platform.h 2013-04-03 18:49:21 +0000
@@ -0,0 +1,52 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_
20#define MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_
21
22#include "input_platform.h"
23
24namespace mir
25{
26namespace client
27{
28namespace input
29{
30namespace android
31{
32
33/// Implementation of client input machinery for android input stack wire protocol.
34class AndroidInputPlatform : public InputPlatform
35{
36public:
37 AndroidInputPlatform();
38 virtual ~AndroidInputPlatform();
39
40 std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback);
41
42protected:
43 AndroidInputPlatform(const AndroidInputPlatform&) = delete;
44 AndroidInputPlatform& operator=(const AndroidInputPlatform&) = delete;
45};
46
47}
48}
49}
50} // namespace mir
51
52#endif // MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_
053
=== added file 'src/client/input/android_input_receiver.cpp'
--- src/client/input/android_input_receiver.cpp 1970-01-01 00:00:00 +0000
+++ src/client/input/android_input_receiver.cpp 2013-04-03 18:49:21 +0000
@@ -0,0 +1,91 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "android_input_receiver.h"
20#include "mir/input/android/android_input_lexicon.h"
21
22#include <androidfw/InputTransport.h>
23#include <utils/Looper.h>
24
25namespace mclia = mir::client::input::android;
26namespace miat = mir::input::android::transport;
27
28mclia::InputReceiver::InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel)
29 : input_channel(input_channel),
30 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
31 looper(new droidinput::Looper(true)),
32 fd_added(false)
33{
34}
35
36mclia::InputReceiver::InputReceiver(int fd)
37 : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)),
38 input_consumer(std::make_shared<droidinput::InputConsumer>(input_channel)),
39 looper(new droidinput::Looper(true)),
40 fd_added(false)
41{
42}
43
44mclia::InputReceiver::~InputReceiver()
45{
46}
47
48int mclia::InputReceiver::fd() const
49{
50 return input_channel->getFd();
51}
52
53// TODO: We use a droidinput::Looper here for polling functionality but it might be nice to integrate
54// with the existing client io_service ~racarr ~tvoss
55bool mclia::InputReceiver::next_event(std::chrono::milliseconds const& timeout, MirEvent &ev)
56{
57 droidinput::InputEvent *android_event;
58 uint32_t event_sequence_id;
59 bool handled_event = false;
60
61 if (!fd_added)
62 {
63 // TODO: Why will this fail from the constructor? ~racarr
64 looper->addFd(fd(), fd(), ALOOPER_EVENT_INPUT, nullptr, nullptr);
65 fd_added = true;
66 }
67
68 auto result = looper->pollOnce(timeout.count());
69 if (result == ALOOPER_POLL_WAKE)
70 return false;
71 else if (result == ALOOPER_POLL_ERROR) // TODO: Exception?
72 return false;
73
74 if(input_consumer->consume(&event_factory, true,
75 -1, &event_sequence_id, &android_event) != droidinput::WOULD_BLOCK)
76 {
77 miat::Lexicon::translate(android_event, ev);
78 input_consumer->sendFinishedSignal(event_sequence_id, true);
79 handled_event = true;
80 }
81
82 // So far once we have sent an event to the client there is no chance for redispatch
83 // so the client handles all events.
84
85 return handled_event;
86}
87
88void mclia::InputReceiver::wake()
89{
90 looper->wake();
91}
092
=== added file 'src/client/input/android_input_receiver.h'
--- src/client/input/android_input_receiver.h 1970-01-01 00:00:00 +0000
+++ src/client/input/android_input_receiver.h 2013-04-03 18:49:21 +0000
@@ -0,0 +1,84 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_INPUT_ANDROID_INPUT_RECEIVER_H_
20#define MIR_INPUT_ANDROID_INPUT_RECEIVER_H_
21
22#include "mir_toolkit/input/event.h"
23
24#include <utils/StrongPointer.h>
25#include <androidfw/Input.h>
26
27#include <memory>
28#include <chrono>
29
30namespace droidinput = android;
31
32namespace android
33{
34class InputChannel;
35class InputConsumer;
36class Looper;
37}
38
39namespace mir
40{
41namespace client
42{
43namespace input
44{
45namespace android
46{
47
48/// Synchronously receives input events in a blocking manner
49class InputReceiver
50{
51public:
52 InputReceiver(droidinput::sp<droidinput::InputChannel> const& input_channel);
53 InputReceiver(int fd);
54
55 virtual ~InputReceiver();
56 int fd() const;
57
58 /// Synchronously receive an event with millisecond timeout. A negative timeout value
59 /// is used to request indefinite polling.
60 virtual bool next_event(std::chrono::milliseconds const& timeout, MirEvent &ev);
61 virtual bool next_event(MirEvent &ev) { return next_event(std::chrono::milliseconds(-1), ev); }
62
63 /// May be used from any thread to wake an InputReceiver blocked in next_event
64 virtual void wake();
65
66protected:
67 InputReceiver(const InputReceiver&) = delete;
68 InputReceiver& operator=(const InputReceiver&) = delete;
69
70private:
71 droidinput::sp<droidinput::InputChannel> input_channel;
72 std::shared_ptr<droidinput::InputConsumer> input_consumer;
73 droidinput::PreallocatedInputEventFactory event_factory;
74 droidinput::sp<droidinput::Looper> looper;
75
76 bool fd_added;
77};
78
79}
80}
81}
82} // namespace mir
83
84#endif // MIR_INPUT_ANDROID_INPUT_RECEIVER_H_
085
=== added file 'src/client/input/android_input_receiver_thread.cpp'
--- src/client/input/android_input_receiver_thread.cpp 1970-01-01 00:00:00 +0000
+++ src/client/input/android_input_receiver_thread.cpp 2013-04-03 18:49:21 +0000
@@ -0,0 +1,68 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "android_input_receiver_thread.h"
20#include "android_input_receiver.h"
21
22#include <thread>
23
24namespace mclia = mir::client::input::android;
25
26mclia::InputReceiverThread::InputReceiverThread(std::shared_ptr<mclia::InputReceiver> const& receiver,
27 std::function<void(MirEvent*)> const& event_handling_callback)
28 : receiver(receiver),
29 handler(event_handling_callback),
30 running(false)
31{
32}
33
34mclia::InputReceiverThread::~InputReceiverThread()
35{
36 if (running)
37 stop();
38 if (thread.joinable())
39 join();
40}
41
42void mclia::InputReceiverThread::start()
43{
44 running = true;
45 thread = std::thread(std::mem_fn(&mclia::InputReceiverThread::thread_loop), this);
46}
47
48void mclia::InputReceiverThread::stop()
49{
50 running = false;
51 receiver->wake();
52}
53
54void mclia::InputReceiverThread::join()
55{
56 thread.join();
57}
58
59void mclia::InputReceiverThread::thread_loop()
60{
61 while (running)
62 {
63 MirEvent ev;
64 while(running && receiver->next_event(ev))
65 handler(&ev);
66 std::this_thread::yield(); // yield() is needed to ensure reasonable runtime under valgrind
67 }
68}
069
=== added file 'src/client/input/android_input_receiver_thread.h'
--- src/client/input/android_input_receiver_thread.h 1970-01-01 00:00:00 +0000
+++ src/client/input/android_input_receiver_thread.h 2013-04-03 18:49:21 +0000
@@ -0,0 +1,71 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_INPUT_ANDROID_INPUT_RECEIVER_THREAD_H_
20#define MIR_INPUT_ANDROID_INPUT_RECEIVER_THREAD_H_
21
22#include "input_receiver_thread.h"
23
24#include "mir_toolkit/input/event.h"
25
26#include <functional>
27#include <memory>
28#include <atomic>
29#include <thread>
30
31namespace mir
32{
33namespace client
34{
35namespace input
36{
37namespace android
38{
39class InputReceiver;
40
41/// Responsible for polling an InputReceiver to read and dispatch events when appropriate.
42class InputReceiverThread : public input::InputReceiverThread
43{
44public:
45 InputReceiverThread(std::shared_ptr<InputReceiver> const& receiver,
46 std::function<void(MirEvent*)> const& event_handling_callback);
47 virtual ~InputReceiverThread();
48
49 void start();
50 void stop();
51 void join();
52
53protected:
54 InputReceiverThread(const InputReceiverThread&) = delete;
55 InputReceiverThread& operator=(const InputReceiverThread&) = delete;
56
57private:
58 std::shared_ptr<InputReceiver> const receiver;
59 std::function<void(MirEvent*)> const handler;
60
61 void thread_loop();
62 std::atomic<bool> running;
63 std::thread thread;
64};
65
66}
67}
68}
69} // namespace mir
70
71#endif // MIR_INPUT_ANDROID_INPUT_RECEIVER_THREAD_H_
072
=== added file 'src/client/input/input_platform.h'
--- src/client/input/input_platform.h 1970-01-01 00:00:00 +0000
+++ src/client/input/input_platform.h 2013-04-03 18:49:21 +0000
@@ -0,0 +1,55 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_INPUT_PLATFORM_H_
20#define MIR_CLIENT_INPUT_PLATFORM_H_
21
22#include "mir_toolkit/input/event.h"
23
24#include <memory>
25#include <functional>
26
27namespace mir
28{
29namespace client
30{
31namespace input
32{
33class InputReceiverThread;
34
35// Interface for MirSurface to construct input dispatcher threads.
36class InputPlatform
37{
38public:
39 virtual ~InputPlatform() {};
40
41 virtual std::shared_ptr<InputReceiverThread> create_input_thread(int fd, std::function<void(MirEvent *)> const& callback) = 0;
42
43 static std::shared_ptr<InputPlatform> create();
44
45protected:
46 InputPlatform() = default;
47 InputPlatform(const InputPlatform&) = delete;
48 InputPlatform& operator=(const InputPlatform&) = delete;
49};
50
51}
52}
53} // namespace mir
54
55#endif // MIR_CLIENT_INPUT_PLATFORM_H_
056
=== added file 'src/client/input/input_receiver_thread.h'
--- src/client/input/input_receiver_thread.h 1970-01-01 00:00:00 +0000
+++ src/client/input/input_receiver_thread.h 2013-04-03 18:49:21 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_INPUT_RECEIVER_THREAD_H_
20#define MIR_CLIENT_INPUT_RECEIVER_THREAD_H_
21
22namespace mir
23{
24namespace client
25{
26namespace input
27{
28
29class InputReceiverThread
30{
31public:
32 virtual ~InputReceiverThread() {};
33
34 virtual void start() = 0;
35 virtual void stop() = 0;
36 virtual void join() = 0;
37
38protected:
39 InputReceiverThread() = default;
40 InputReceiverThread(const InputReceiverThread&) = delete;
41 InputReceiverThread& operator=(const InputReceiverThread&) = delete;
42};
43
44}
45}
46} // namespace mir
47
48#endif // MIR_CLIENT_INPUT_RECEIVER_THREAD_H_
049
=== modified file 'src/client/mir_client_library.cpp'
--- src/client/mir_client_library.cpp 2013-03-29 11:27:00 +0000
+++ src/client/mir_client_library.cpp 2013-04-03 18:49:21 +0000
@@ -118,16 +118,17 @@
118}118}
119119
120MirWaitHandle* mir_surface_create(120MirWaitHandle* mir_surface_create(
121 MirConnection * connection,121 MirConnection* connection,
122 MirSurfaceParameters const * params,122 MirSurfaceParameters const* params,
123 MirEventDelegate const* delegate,
123 mir_surface_lifecycle_callback callback,124 mir_surface_lifecycle_callback callback,
124 void * context)125 void* context)
125{126{
126 if (&error_connection == connection) return 0;127 if (&error_connection == connection) return 0;
127128
128 try129 try
129 {130 {
130 return connection->create_surface(*params, callback, context);131 return connection->create_surface(*params, delegate, callback, context);
131 }132 }
132 catch (std::exception const&)133 catch (std::exception const&)
133 {134 {
@@ -137,12 +138,15 @@
137138
138}139}
139140
140MirSurface *mir_surface_create_sync(141MirSurface* mir_surface_create_sync(
141 MirConnection *connection, MirSurfaceParameters const *params)142 MirConnection* connection,
143 MirSurfaceParameters const* params,
144 MirEventDelegate const* delegate)
142{145{
143 MirSurface *surface = nullptr;146 MirSurface *surface = nullptr;
144147
145 mir_wait_for(mir_surface_create(connection, params,148 mir_wait_for(mir_surface_create(connection, params,
149 delegate,
146 reinterpret_cast<mir_surface_lifecycle_callback>(assign_result),150 reinterpret_cast<mir_surface_lifecycle_callback>(assign_result),
147 &surface));151 &surface));
148152
149153
=== modified file 'src/client/mir_client_surface.h'
--- src/client/mir_client_surface.h 2013-03-29 11:27:00 +0000
+++ src/client/mir_client_surface.h 2013-04-03 18:49:21 +0000
@@ -22,6 +22,7 @@
22#include "mir_toolkit/mir_client_library.h"22#include "mir_toolkit/mir_client_library.h"
2323
24#include <memory>24#include <memory>
25
25namespace mir26namespace mir
26{27{
27namespace client28namespace client
2829
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2013-03-29 11:27:00 +0000
+++ src/client/mir_connection.cpp 2013-04-03 18:49:21 +0000
@@ -25,10 +25,13 @@
25#include "client_buffer_depository.h"25#include "client_buffer_depository.h"
26#include "make_rpc_channel.h"26#include "make_rpc_channel.h"
2727
28#include "input/input_platform.h"
29
28#include <thread>30#include <thread>
29#include <cstddef>31#include <cstddef>
3032
31namespace mcl = mir::client;33namespace mcl = mir::client;
34namespace mcli = mcl::input;
32namespace mp = mir::protobuf;35namespace mp = mir::protobuf;
33namespace gp = google::protobuf;36namespace gp = google::protobuf;
3437
@@ -46,7 +49,8 @@
46 channel(channel),49 channel(channel),
47 server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL),50 server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL),
48 log(log),51 log(log),
49 client_platform_factory(client_platform_factory)52 client_platform_factory(client_platform_factory),
53 input_platform(mcli::InputPlatform::create())
50{54{
51 {55 {
52 std::lock_guard<std::mutex> lock(connection_guard);56 std::lock_guard<std::mutex> lock(connection_guard);
@@ -63,11 +67,13 @@
6367
64MirWaitHandle* MirConnection::create_surface(68MirWaitHandle* MirConnection::create_surface(
65 MirSurfaceParameters const & params,69 MirSurfaceParameters const & params,
70 MirEventDelegate const* delegate,
66 mir_surface_lifecycle_callback callback,71 mir_surface_lifecycle_callback callback,
67 void * context)72 void * context)
68{73{
69 auto null_log = std::make_shared<mir::client::NullLogger>();74 auto null_log = std::make_shared<mir::client::NullLogger>();
70 auto surface = new MirSurface(this, server, null_log, platform->create_buffer_factory(), params, callback, context);75 auto surface = new MirSurface(this, server, null_log, platform->create_buffer_factory(), input_platform, params, delegate, callback, context);
76
71 return surface->get_create_wait_handle();77 return surface->get_create_wait_handle();
72}78}
7379
7480
=== modified file 'src/client/mir_connection.h'
--- src/client/mir_connection.h 2013-04-02 09:23:02 +0000
+++ src/client/mir_connection.h 2013-04-03 18:49:21 +0000
@@ -42,6 +42,10 @@
42class Logger;42class Logger;
43class ClientBufferDepository;43class ClientBufferDepository;
44class ClientPlatformFactory;44class ClientPlatformFactory;
45namespace input
46{
47class InputPlatform;
48}
45}49}
46}50}
4751
@@ -60,6 +64,7 @@
6064
61 MirWaitHandle* create_surface(65 MirWaitHandle* create_surface(
62 MirSurfaceParameters const & params,66 MirSurfaceParameters const & params,
67 MirEventDelegate const* delegate,
63 mir_surface_lifecycle_callback callback,68 mir_surface_lifecycle_callback callback,
64 void * context);69 void * context);
65 MirWaitHandle* release_surface(70 MirWaitHandle* release_surface(
@@ -114,6 +119,8 @@
114 std::shared_ptr<mir::client::ClientPlatform> platform;119 std::shared_ptr<mir::client::ClientPlatform> platform;
115 std::shared_ptr<EGLNativeDisplayType> native_display;120 std::shared_ptr<EGLNativeDisplayType> native_display;
116121
122 std::shared_ptr<mir::client::input::InputPlatform> const input_platform;
123
117 std::string error_message;124 std::string error_message;
118125
119 MirWaitHandle connect_wait_handle;126 MirWaitHandle connect_wait_handle;
120127
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2013-04-02 09:23:02 +0000
+++ src/client/mir_surface.cpp 2013-04-03 18:49:21 +0000
@@ -21,11 +21,14 @@
21#include "client_buffer.h"21#include "client_buffer.h"
22#include "mir_surface.h"22#include "mir_surface.h"
23#include "mir_connection.h"23#include "mir_connection.h"
24#include "input/input_receiver_thread.h"
25#include "input/input_platform.h"
2426
25#include <cassert>27#include <cassert>
2628
27namespace geom = mir::geometry;29namespace geom = mir::geometry;
28namespace mcl = mir::client;30namespace mcl = mir::client;
31namespace mcli = mir::client::input;
29namespace mp = mir::protobuf;32namespace mp = mir::protobuf;
30namespace gp = google::protobuf;33namespace gp = google::protobuf;
3134
@@ -34,11 +37,14 @@
34 mp::DisplayServer::Stub & server,37 mp::DisplayServer::Stub & server,
35 std::shared_ptr<mir::client::Logger> const& logger,38 std::shared_ptr<mir::client::Logger> const& logger,
36 std::shared_ptr<mcl::ClientBufferFactory> const& factory,39 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
37 MirSurfaceParameters const& params,40 std::shared_ptr<mcli::InputPlatform> const& input_platform,
41 MirSurfaceParameters const & params,
42 MirEventDelegate const* delegate,
38 mir_surface_lifecycle_callback callback, void * context)43 mir_surface_lifecycle_callback callback, void * context)
39 : server(server),44 : server(server),
40 connection(allocating_connection),45 connection(allocating_connection),
41 buffer_depository(std::make_shared<mcl::ClientBufferDepository>(factory, 3)),46 buffer_depository(std::make_shared<mcl::ClientBufferDepository>(factory, 3)),
47 input_platform(input_platform),
42 logger(logger)48 logger(logger)
43{49{
44 mir::protobuf::SurfaceParameters message;50 mir::protobuf::SurfaceParameters message;
@@ -47,6 +53,9 @@
47 message.set_height(params.height);53 message.set_height(params.height);
48 message.set_pixel_format(params.pixel_format);54 message.set_pixel_format(params.pixel_format);
49 message.set_buffer_usage(params.buffer_usage);55 message.set_buffer_usage(params.buffer_usage);
56
57 if (delegate)
58 handle_event_callback = std::bind(delegate->handle_input, this, std::placeholders::_1, delegate->context);
5059
51 server.create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));60 server.create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));
5261
@@ -57,6 +66,8 @@
5766
58MirSurface::~MirSurface()67MirSurface::~MirSurface()
59{68{
69 if (input_thread)
70 input_thread->stop();
60 release_cpu_region();71 release_cpu_region();
61}72}
6273
@@ -166,6 +177,13 @@
166 accelerated_window = platform->create_egl_native_window(this);177 accelerated_window = platform->create_egl_native_window(this);
167178
168 callback(this, context);179 callback(this, context);
180
181 if (surface.fd_size() > 0 && handle_event_callback)
182 {
183 input_thread = input_platform->create_input_thread(surface.fd(0), handle_event_callback);
184 input_thread->start();
185 }
186
169 create_wait_handle.result_received();187 create_wait_handle.result_received();
170}188}
171189
172190
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2013-03-29 11:27:00 +0000
+++ src/client/mir_surface.h 2013-04-03 18:49:21 +0000
@@ -30,12 +30,19 @@
30#include "client_platform.h"30#include "client_platform.h"
3131
32#include <memory>32#include <memory>
33#include <functional>
3334
34namespace mir35namespace mir
35{36{
36namespace client37namespace client
37{38{
38class ClientBuffer;39class ClientBuffer;
40namespace input
41{
42class InputPlatform;
43class InputReceiverThread;
44}
45
39struct MemoryRegion;46struct MemoryRegion;
40}47}
41}48}
@@ -51,7 +58,9 @@
51 mir::protobuf::DisplayServer::Stub & server,58 mir::protobuf::DisplayServer::Stub & server,
52 std::shared_ptr<mir::client::Logger> const& logger,59 std::shared_ptr<mir::client::Logger> const& logger,
53 std::shared_ptr<mir::client::ClientBufferFactory> const& buffer_factory,60 std::shared_ptr<mir::client::ClientBufferFactory> const& buffer_factory,
61 std::shared_ptr<mir::client::input::InputPlatform> const& input_platform,
54 MirSurfaceParameters const& params,62 MirSurfaceParameters const& params,
63 MirEventDelegate const* delegate,
55 mir_surface_lifecycle_callback callback, void * context);64 mir_surface_lifecycle_callback callback, void * context);
5665
57 ~MirSurface();66 ~MirSurface();
@@ -97,6 +106,7 @@
97106
98 std::shared_ptr<mir::client::MemoryRegion> secured_region;107 std::shared_ptr<mir::client::MemoryRegion> secured_region;
99 std::shared_ptr<mir::client::ClientBufferDepository> buffer_depository;108 std::shared_ptr<mir::client::ClientBufferDepository> buffer_depository;
109 std::shared_ptr<mir::client::input::InputPlatform> const input_platform;
100110
101 std::shared_ptr<mir::client::Logger> logger;111 std::shared_ptr<mir::client::Logger> logger;
102 std::shared_ptr<EGLNativeWindowType> accelerated_window;112 std::shared_ptr<EGLNativeWindowType> accelerated_window;
@@ -105,6 +115,9 @@
105115
106 // Cache of latest SurfaceSettings returned from the server116 // Cache of latest SurfaceSettings returned from the server
107 int attrib_cache[mir_surface_attrib_arraysize_];117 int attrib_cache[mir_surface_attrib_arraysize_];
118
119 std::function<void(MirEvent*)> handle_event_callback;
120 std::shared_ptr<mir::client::input::InputReceiverThread> input_thread;
108};121};
109122
110#endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */123#endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */
111124
=== modified file 'src/server/CMakeLists.txt'
--- src/server/CMakeLists.txt 2013-03-29 10:44:42 +0000
+++ src/server/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -51,6 +51,7 @@
51 mirfrontend51 mirfrontend
52 mirgraphics52 mirgraphics
53 mirinput53 mirinput
54 mirinputandroidtransport
54 mirsurfaces55 mirsurfaces
55 mirtime56 mirtime
56)57)
5758
=== modified file 'src/server/default_server_configuration.cpp'
--- src/server/default_server_configuration.cpp 2013-03-28 14:20:06 +0000
+++ src/server/default_server_configuration.cpp 2013-04-03 18:49:21 +0000
@@ -44,6 +44,7 @@
44#include "mir/graphics/buffer_initializer.h"44#include "mir/graphics/buffer_initializer.h"
45#include "mir/graphics/null_display_report.h"45#include "mir/graphics/null_display_report.h"
46#include "mir/input/input_manager.h"46#include "mir/input/input_manager.h"
47#include "mir/input/null_input_manager.h"
47#include "mir/logging/logger.h"48#include "mir/logging/logger.h"
48#include "mir/logging/dumb_console_logger.h"49#include "mir/logging/dumb_console_logger.h"
49#include "mir/logging/glog_logger.h"50#include "mir/logging/glog_logger.h"
@@ -140,6 +141,7 @@
140 "Environment variables capitalise long form with prefix \"MIR_SERVER_\" and \"_\" in place of \"-\"");141 "Environment variables capitalise long form with prefix \"MIR_SERVER_\" and \"_\" in place of \"-\"");
141 desc.add_options()142 desc.add_options()
142 ("file,f", po::value<std::string>(), "Socket filename")143 ("file,f", po::value<std::string>(), "Socket filename")
144 ("enable-input,i", po::value<bool>(), "Enable input. [bool:default=false]")
143 (log_display, po::value<bool>(), "Log the Display report. [bool:default=false]")145 (log_display, po::value<bool>(), "Log the Display report. [bool:default=false]")
144 (log_app_mediator, po::value<bool>(), "Log the ApplicationMediator report. [bool:default=false]")146 (log_app_mediator, po::value<bool>(), "Log the ApplicationMediator report. [bool:default=false]")
145 (log_msg_processor, po::value<bool>(), "log the MessageProcessor report")147 (log_msg_processor, po::value<bool>(), "log the MessageProcessor report")
@@ -316,9 +318,12 @@
316mir::DefaultServerConfiguration::the_input_manager()318mir::DefaultServerConfiguration::the_input_manager()
317{319{
318 return input_manager(320 return input_manager(
319 [&, this]()321 [&, this]() -> std::shared_ptr<mi::InputManager>
320 {322 {
321 return mi::create_input_manager(the_event_filters(), the_display());323 if (the_options()->get("enable-input", false))
324 return mi::create_input_manager(the_event_filters(), the_display());
325 else
326 return std::make_shared<mi::NullInputManager>();
322 });327 });
323}328}
324329
325330
=== modified file 'src/server/frontend/protobuf_message_processor.cpp'
--- src/server/frontend/protobuf_message_processor.cpp 2013-03-22 03:33:00 +0000
+++ src/server/frontend/protobuf_message_processor.cpp 2013-04-03 18:49:21 +0000
@@ -73,12 +73,14 @@
7373
74void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, mir::protobuf::Surface* response)74void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, mir::protobuf::Surface* response)
75{75{
76 const auto& fd = response->has_buffer() ?76 auto const& surface_fd = extract_fds_from(response);
77 const auto& buffer_fd = response->has_buffer() ?
77 extract_fds_from(response->mutable_buffer()) :78 extract_fds_from(response->mutable_buffer()) :
78 std::vector<int32_t>();79 std::vector<int32_t>();
7980
80 send_response(id, static_cast<google::protobuf::Message*>(response));81 send_response(id, static_cast<google::protobuf::Message*>(response));
81 sender->send_fds(fd);82 sender->send_fds(surface_fd);
83 sender->send_fds(buffer_fd);
82 resource_cache->free_resource(response);84 resource_cache->free_resource(response);
83}85}
8486
8587
=== modified file 'src/server/input/CMakeLists.txt'
--- src/server/input/CMakeLists.txt 2013-03-13 04:54:15 +0000
+++ src/server/input/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -4,14 +4,7 @@
4 event_filter_chain.cpp4 event_filter_chain.cpp
5)5)
66
7if (NOT MIR_DISABLE_INPUT)
8add_subdirectory(android)7add_subdirectory(android)
9else()
10list(
11 APPEND INPUT_SOURCES
12 dummy_input_manager.cpp
13)
14endif()
158
16add_library(9add_library(
17 mirinput STATIC10 mirinput STATIC
1811
=== modified file 'src/server/input/android/CMakeLists.txt'
--- src/server/input/android/CMakeLists.txt 2013-03-22 16:41:59 +0000
+++ src/server/input/android/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -3,7 +3,6 @@
3 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_manager.cpp3 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_manager.cpp
4 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_reader_policy.cpp4 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_reader_policy.cpp
5 ${CMAKE_CURRENT_SOURCE_DIR}/android_pointer_controller.cpp5 ${CMAKE_CURRENT_SOURCE_DIR}/android_pointer_controller.cpp
6 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_lexicon.cpp
7 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_channel.cpp6 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_channel.cpp
8 ${CMAKE_CURRENT_SOURCE_DIR}/rudimentary_input_reader_policy.cpp7 ${CMAKE_CURRENT_SOURCE_DIR}/rudimentary_input_reader_policy.cpp
9 ${CMAKE_CURRENT_SOURCE_DIR}/event_filter_dispatcher_policy.cpp8 ${CMAKE_CURRENT_SOURCE_DIR}/event_filter_dispatcher_policy.cpp
@@ -18,3 +17,4 @@
18 PARENT_SCOPE17 PARENT_SCOPE
19)18)
2019
20add_subdirectory(transport)
2121
=== modified file 'src/server/input/android/android_input_application_handle.cpp'
--- src/server/input/android/android_input_application_handle.cpp 2013-03-20 22:42:09 +0000
+++ src/server/input/android/android_input_application_handle.cpp 2013-04-03 18:49:21 +0000
@@ -26,7 +26,7 @@
26namespace mia = mi::android;26namespace mia = mi::android;
2727
28mia::InputApplicationHandle::InputApplicationHandle(std::shared_ptr<mi::SessionTarget> const& session)28mia::InputApplicationHandle::InputApplicationHandle(std::shared_ptr<mi::SessionTarget> const& session)
29 : session(session)29 : weak_session(session)
30{30{
31 updateInfo();31 updateInfo();
32}32}
@@ -35,6 +35,11 @@
35{35{
36 if (mInfo == NULL)36 if (mInfo == NULL)
37 mInfo = new droidinput::InputApplicationInfo;37 mInfo = new droidinput::InputApplicationInfo;
38
39 auto session = weak_session.lock();
40 if (!session)
41 return false;
42
38 mInfo->dispatchingTimeout = INT_MAX;43 mInfo->dispatchingTimeout = INT_MAX;
39 mInfo->name = droidinput::String8(session->name().c_str());44 mInfo->name = droidinput::String8(session->name().c_str());
4045
4146
=== modified file 'src/server/input/android/android_input_application_handle.h'
--- src/server/input/android/android_input_application_handle.h 2013-03-20 22:42:09 +0000
+++ src/server/input/android/android_input_application_handle.h 2013-04-03 18:49:21 +0000
@@ -48,7 +48,7 @@
48 InputApplicationHandle& operator=(InputApplicationHandle const&) = delete;48 InputApplicationHandle& operator=(InputApplicationHandle const&) = delete;
4949
50private:50private:
51 std::shared_ptr<input::SessionTarget> session;51 std::weak_ptr<input::SessionTarget> weak_session;
52};52};
5353
54}54}
5555
=== modified file 'src/server/input/android/event_filter_dispatcher_policy.cpp'
--- src/server/input/android/event_filter_dispatcher_policy.cpp 2013-03-22 16:41:59 +0000
+++ src/server/input/android/event_filter_dispatcher_policy.cpp 2013-04-03 18:49:21 +0000
@@ -16,10 +16,11 @@
16 * Authored by: Robert Carr <robert.carr@canonical.com>16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */17 */
18#include "event_filter_dispatcher_policy.h"18#include "event_filter_dispatcher_policy.h"
19#include "android_input_lexicon.h"19#include "mir/input/android/android_input_lexicon.h"
2020
21namespace mi = mir::input;21namespace mi = mir::input;
22namespace mia = mi::android;22namespace mia = mi::android;
23namespace miat = mia::transport;
2324
24mia::EventFilterDispatcherPolicy::EventFilterDispatcherPolicy(std::shared_ptr<mi::EventFilter> const& event_filter) :25mia::EventFilterDispatcherPolicy::EventFilterDispatcherPolicy(std::shared_ptr<mi::EventFilter> const& event_filter) :
25 event_filter(event_filter)26 event_filter(event_filter)
@@ -29,7 +30,7 @@
29bool mia::EventFilterDispatcherPolicy::filterInputEvent(const droidinput::InputEvent* input_event, uint32_t /*policy_flags*/)30bool mia::EventFilterDispatcherPolicy::filterInputEvent(const droidinput::InputEvent* input_event, uint32_t /*policy_flags*/)
30{31{
31 MirEvent mir_ev;32 MirEvent mir_ev;
32 mia::Lexicon::translate(input_event, mir_ev);33 miat::Lexicon::translate(input_event, mir_ev);
3334
34 if (event_filter->handles(mir_ev))35 if (event_filter->handles(mir_ev))
35 return false; /* Do not pass the event on */36 return false; /* Do not pass the event on */
3637
=== added directory 'src/server/input/android/transport'
=== added file 'src/server/input/android/transport/CMakeLists.txt'
--- src/server/input/android/transport/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/server/input/android/transport/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -0,0 +1,31 @@
1# Copyright © 2012 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License version 3 as
5# published by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14#
15# Authored by: Thomas Voss <thomas.voss@canonical.com>
16
17set(
18 ANDROID_TRANSPORT_SOURCES
19 ${CMAKE_CURRENT_SOURCE_DIR}/android_input_lexicon.cpp
20)
21
22add_library(
23 mirinputandroidtransport STATIC
24 ${ANDROID_TRANSPORT_SOURCES}
25)
26
27target_link_libraries(
28 mirinputandroidtransport
29
30 android-input
31)
032
=== renamed file 'src/server/input/android/android_input_lexicon.cpp' => 'src/server/input/android/transport/android_input_lexicon.cpp'
--- src/server/input/android/android_input_lexicon.cpp 2013-03-13 04:54:15 +0000
+++ src/server/input/android/transport/android_input_lexicon.cpp 2013-04-03 18:49:21 +0000
@@ -1,29 +1,29 @@
1/*1/*
2 * Copyright © 2012 Canonical Ltd.2 * Copyright © 2012 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify
5 * under the terms of the GNU Lesser General Public License version 3,5 * it under the terms of the GNU General Public License version 3 as
6 * as published by the Free Software Foundation.6 * published by the Free Software Foundation.
7 *7 *
8 * This program is distributed in the hope that it will be useful,8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.11 * GNU General Public License for more details.
12 *12 *
13 * You should have received a copy of the GNU Lesser General Public License13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Thomas Voss <thomas.voss@canonical.com>16 * Authored by: Thomas Voss <thomas.voss@canonical.com>
17 * Robert Carr <robert.carr@canonical.com>17 * Robert Carr <robert.carr@canonical.com>
18 */18 */
1919
20#include "android_input_lexicon.h"20#include "mir/input/android/android_input_lexicon.h"
2121
22#include <androidfw/Input.h>22#include <androidfw/Input.h>
2323
24namespace mia = mir::input::android;24namespace miat = mir::input::android::transport;
2525
26void mia::Lexicon::translate(const droidinput::InputEvent *android_event, MirEvent &mir_event)26void miat::Lexicon::translate(const droidinput::InputEvent *android_event, MirEvent &mir_event)
27{27{
28 switch(android_event->getType())28 switch(android_event->getType())
29 {29 {
3030
=== removed file 'src/server/input/dummy_input_manager.cpp'
--- src/server/input/dummy_input_manager.cpp 2013-03-29 16:51:35 +0000
+++ src/server/input/dummy_input_manager.cpp 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
1/*
2 * Copyright © 2012 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#include "mir/input/input_manager.h"
20
21namespace mg = mir::graphics;
22namespace mi = mir::input;
23
24namespace
25{
26class DummyInputManager : public mi::InputManager
27{
28 void stop() {}
29 void start() {}
30 virtual std::shared_ptr<mi::InputChannel> make_input_channel() { return std::shared_ptr<mi::InputChannel>(); }
31 void set_input_focus_to(std::shared_ptr<mi::SessionTarget> const& /* session */, std::shared_ptr<mi::SurfaceTarget> const& /* surface */)
32 {
33 }
34};
35}
36
37std::shared_ptr<mi::InputManager> mi::create_input_manager(
38 const std::initializer_list<std::shared_ptr<mi::EventFilter> const>& ,
39 std::shared_ptr<mg::ViewableArea> const& )
40{
41 return std::make_shared<DummyInputManager>();
42}
430
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2013-03-29 22:30:35 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -13,6 +13,9 @@
13)13)
1414
15list(APPEND SOURCES15list(APPEND SOURCES
16 test_client_input.cpp)
17
18list(APPEND SOURCES
16 test_server_startup.cpp19 test_server_startup.cpp
17)20)
1821
@@ -21,6 +24,7 @@
2124
22 ${SOURCES}25 ${SOURCES}
23)26)
27uses_android_input(acceptance-tests)
2428
2529
26target_link_libraries(30target_link_libraries(
2731
=== added file 'tests/acceptance-tests/test_client_input.cpp'
--- tests/acceptance-tests/test_client_input.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/test_client_input.cpp 2013-04-03 18:49:21 +0000
@@ -0,0 +1,268 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "mir/graphics/display.h"
20
21#include "src/server/input/android/android_input_manager.h"
22
23#include "mir_toolkit/mir_client_library.h"
24
25#include "mir_test/fake_shared.h"
26#include "mir_test/fake_event_hub_input_configuration.h"
27#include "mir_test/fake_event_hub.h"
28#include "mir_test/event_factory.h"
29#include "mir_test/wait_condition.h"
30#include "mir_test_framework/display_server_test_fixture.h"
31
32#include <gtest/gtest.h>
33#include <gmock/gmock.h>
34
35#include <thread>
36#include <functional>
37
38namespace mi = mir::input;
39namespace mia = mi::android;
40namespace mis = mi::synthesis;
41namespace mt = mir::test;
42namespace mtd = mt::doubles;
43namespace mtf = mir_test_framework;
44
45namespace
46{
47 char const* const mir_test_socket = mtf::test_socket_file().c_str();
48}
49
50namespace
51{
52
53struct FocusNotifyingInputManager : public mia::InputManager
54{
55 FocusNotifyingInputManager(std::shared_ptr<mia::InputConfiguration> const& configuration,
56 mt::WaitCondition &wait_condition)
57 : InputManager(configuration),
58 on_focus_set(wait_condition)
59 {
60
61 }
62
63 void set_input_focus_to(
64 std::shared_ptr<mi::SessionTarget> const& session, std::shared_ptr<mi::SurfaceTarget> const& surface) override
65 {
66 InputManager::set_input_focus_to(session, surface);
67
68 // We need a synchronization primitive inorder to halt test event injection
69 // until after a surface has taken focus (lest the events be discarded).
70 if (surface)
71 on_focus_set.wake_up_everyone();
72 }
73
74 mt::WaitCondition &on_focus_set;
75};
76
77struct FakeInputServerConfiguration : public mir_test_framework::TestingServerConfiguration
78{
79 FakeInputServerConfiguration()
80 : input_config(the_event_filters(), the_display(), std::shared_ptr<mi::CursorListener>())
81 {
82 }
83
84 virtual void inject_input()
85 {
86 }
87
88 void exec(mir::DisplayServer* /* display_server */) override
89 {
90 input_injection_thread = std::thread([this]() -> void
91 {
92 on_focus_set.wait_for_at_most_seconds(10);
93 fake_event_hub->synthesize_builtin_keyboard_added();
94 fake_event_hub->synthesize_device_scan_complete();
95 inject_input();
96 });
97 }
98
99 void on_exit() override
100 {
101 input_injection_thread.join();
102 }
103
104 std::shared_ptr<mi::InputManager>
105 the_input_manager() override
106 {
107 fake_event_hub = input_config.the_fake_event_hub();
108
109 return input_manager(
110 [this]() -> std::shared_ptr<mi::InputManager>
111 {
112 return std::make_shared<FocusNotifyingInputManager>(mt::fake_shared(input_config), on_focus_set);
113 });
114 }
115
116 mtd::FakeEventHubInputConfiguration input_config;
117 mia::FakeEventHub* fake_event_hub;
118 mt::WaitCondition on_focus_set;
119 std::thread input_injection_thread;
120};
121
122
123struct ClientConfigCommon : TestingClientConfiguration
124{
125 ClientConfigCommon() :
126 connection(0),
127 surface(0)
128 {
129 }
130
131 static void connection_callback(MirConnection* connection, void* context)
132 {
133 ClientConfigCommon* config = reinterpret_cast<ClientConfigCommon *>(context);
134 config->connection = connection;
135 }
136
137 static void create_surface_callback(MirSurface* surface, void* context)
138 {
139 ClientConfigCommon* config = reinterpret_cast<ClientConfigCommon *>(context);
140 config->surface_created(surface);
141 }
142
143 static void release_surface_callback(MirSurface* surface, void* context)
144 {
145 ClientConfigCommon* config = reinterpret_cast<ClientConfigCommon *>(context);
146 config->surface_released(surface);
147 }
148
149 virtual void connected(MirConnection* new_connection)
150 {
151 connection = new_connection;
152 }
153
154 virtual void surface_created(MirSurface* new_surface)
155 {
156 surface = new_surface;
157 }
158
159 virtual void surface_released(MirSurface* /* released_surface */)
160 {
161 surface = NULL;
162 }
163
164 MirConnection* connection;
165 MirSurface* surface;
166};
167
168struct MockInputHandler
169{
170 MOCK_METHOD1(handle_input, void(MirEvent *));
171};
172
173struct InputReceivingClient : ClientConfigCommon
174{
175 InputReceivingClient()
176 : events_received(0)
177 {
178 }
179
180 static void handle_input(MirSurface* /* surface */, MirEvent* ev, void* context)
181 {
182 auto client = static_cast<InputReceivingClient *>(context);
183 client->handler->handle_input(ev);
184 client->event_received[client->events_received].wake_up_everyone();
185 client->events_received++;
186 }
187 virtual void expect_input()
188 {
189 }
190
191 void exec()
192 {
193 handler = std::make_shared<MockInputHandler>();
194
195 expect_input();
196
197 mir_wait_for(mir_connect(
198 mir_test_socket,
199 __PRETTY_FUNCTION__,
200 connection_callback,
201 this));
202 ASSERT_TRUE(connection != NULL);
203 MirSurfaceParameters const request_params =
204 {
205 __PRETTY_FUNCTION__,
206 640, 480,
207 mir_pixel_format_abgr_8888,
208 mir_buffer_usage_hardware
209 };
210 MirEventDelegate const event_delegate =
211 {
212 handle_input,
213 this
214 };
215 mir_wait_for(mir_surface_create(connection, &request_params, &event_delegate, create_surface_callback, this));
216
217 event_received[0].wait_for_at_most_seconds(5);
218 event_received[1].wait_for_at_most_seconds(5);
219 event_received[2].wait_for_at_most_seconds(5);
220
221 mir_surface_release_sync(surface);
222
223 mir_connection_release(connection);
224
225 // ClientConfiguration d'tor is not called on client side so we need this
226 // in order to not leak the Mock object.
227 handler.reset();
228 }
229
230 std::shared_ptr<MockInputHandler> handler;
231 mt::WaitCondition event_received[3];
232 int events_received;
233};
234
235}
236
237using TestClientInput = BespokeDisplayServerTestFixture;
238
239TEST_F(TestClientInput, clients_receive_key_input)
240{
241 using namespace ::testing;
242
243 int const num_events_produced = 3;
244
245 struct InputProducingServerConfiguration : FakeInputServerConfiguration
246 {
247 void inject_input()
248 {
249 // We send multiple events in order to verify the client is handling them
250 // and server dispatch does not become backed up.
251 for (int i = 0; i < num_events_produced; i++)
252 fake_event_hub->synthesize_event(mis::a_key_down_event()
253 .of_scancode(KEY_ENTER));
254 }
255 } server_config;
256 launch_server_process(server_config);
257
258 struct KeyReceivingClient : InputReceivingClient
259 {
260 void expect_input()
261 {
262 using namespace ::testing;
263 EXPECT_CALL(*handler, handle_input(_)).Times(num_events_produced);
264 }
265 } client_config;
266 launch_client_process(client_config);
267}
268
0269
=== modified file 'tests/acceptance-tests/test_client_library.cpp'
--- tests/acceptance-tests/test_client_library.cpp 2013-03-22 10:34:16 +0000
+++ tests/acceptance-tests/test_client_library.cpp 2013-04-03 18:49:21 +0000
@@ -164,7 +164,7 @@
164 mir_buffer_usage_hardware164 mir_buffer_usage_hardware
165 };165 };
166166
167 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));167 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
168168
169 ASSERT_TRUE(surface != NULL);169 ASSERT_TRUE(surface != NULL);
170 EXPECT_TRUE(mir_surface_is_valid(surface));170 EXPECT_TRUE(mir_surface_is_valid(surface));
@@ -182,7 +182,7 @@
182182
183 ASSERT_TRUE(surface == NULL);183 ASSERT_TRUE(surface == NULL);
184184
185 surface = mir_surface_create_sync(connection, &request_params);185 surface = mir_surface_create_sync(connection, &request_params, NULL);
186186
187 ASSERT_TRUE(surface != NULL);187 ASSERT_TRUE(surface != NULL);
188 EXPECT_TRUE(mir_surface_is_valid(surface));188 EXPECT_TRUE(mir_surface_is_valid(surface));
@@ -226,7 +226,7 @@
226 mir_buffer_usage_hardware226 mir_buffer_usage_hardware
227 };227 };
228228
229 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));229 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
230230
231 ASSERT_TRUE(surface != NULL);231 ASSERT_TRUE(surface != NULL);
232 EXPECT_TRUE(mir_surface_is_valid(surface));232 EXPECT_TRUE(mir_surface_is_valid(surface));
@@ -329,7 +329,7 @@
329 mir_buffer_usage_hardware329 mir_buffer_usage_hardware
330 };330 };
331331
332 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));332 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
333333
334 ASSERT_EQ(old_surface_count + 1, current_surface_count());334 ASSERT_EQ(old_surface_count + 1, current_surface_count());
335 }335 }
@@ -377,7 +377,7 @@
377 mir_buffer_usage_hardware377 mir_buffer_usage_hardware
378 };378 };
379379
380 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));380 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
381 ASSERT_TRUE(surface != NULL);381 ASSERT_TRUE(surface != NULL);
382382
383 buffers = 0;383 buffers = 0;
@@ -416,7 +416,7 @@
416 mir_buffer_usage_software416 mir_buffer_usage_software
417 };417 };
418418
419 surface = mir_surface_create_sync(connection, &request_params);419 surface = mir_surface_create_sync(connection, &request_params, NULL);
420 ASSERT_TRUE(surface != NULL);420 ASSERT_TRUE(surface != NULL);
421 EXPECT_TRUE(mir_surface_is_valid(surface));421 EXPECT_TRUE(mir_surface_is_valid(surface));
422 EXPECT_STREQ(mir_surface_get_error_message(surface), "");422 EXPECT_STREQ(mir_surface_get_error_message(surface), "");
@@ -524,7 +524,7 @@
524 mir_buffer_usage_hardware524 mir_buffer_usage_hardware
525 };525 };
526526
527 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));527 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
528// TODO surface_create needs to fail safe too. After that is done we should add the following:528// TODO surface_create needs to fail safe too. After that is done we should add the following:
529// TODO mir_wait_for(mir_surface_next_buffer(surface, next_buffer_callback, this));529// TODO mir_wait_for(mir_surface_next_buffer(surface, next_buffer_callback, this));
530// TODO mir_wait_for(mir_surface_release( surface, release_surface_callback, this));530// TODO mir_wait_for(mir_surface_release( surface, release_surface_callback, this));
531531
=== modified file 'tests/acceptance-tests/test_focus_management_api.cpp'
--- tests/acceptance-tests/test_focus_management_api.cpp 2013-03-22 10:34:16 +0000
+++ tests/acceptance-tests/test_focus_management_api.cpp 2013-04-03 18:49:21 +0000
@@ -226,7 +226,7 @@
226 mir_buffer_usage_hardware226 mir_buffer_usage_hardware
227 };227 };
228228
229 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));229 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
230230
231 set_flag(focus_ready);231 set_flag(focus_ready);
232232
233233
=== modified file 'tests/acceptance-tests/test_focus_selection.cpp'
--- tests/acceptance-tests/test_focus_selection.cpp 2013-03-29 16:51:35 +0000
+++ tests/acceptance-tests/test_focus_selection.cpp 2013-04-03 18:49:21 +0000
@@ -108,7 +108,7 @@
108 mir_pixel_format_abgr_8888,108 mir_pixel_format_abgr_8888,
109 mir_buffer_usage_hardware109 mir_buffer_usage_hardware
110 };110 };
111 mir_wait_for(mir_surface_create(connection, &request_params, create_surface_callback, this));111 mir_wait_for(mir_surface_create(connection, &request_params, NULL, create_surface_callback, this));
112 mir_connection_release(connection);112 mir_connection_release(connection);
113 }113 }
114};114};
115115
=== modified file 'tests/acceptance-tests/test_surfaceloop.cpp'
--- tests/acceptance-tests/test_surfaceloop.cpp 2013-03-22 10:34:16 +0000
+++ tests/acceptance-tests/test_surfaceloop.cpp 2013-04-03 18:49:21 +0000
@@ -172,13 +172,13 @@
172 mir_buffer_usage_hardware172 mir_buffer_usage_hardware
173 };173 };
174174
175 mir_surface_create(connection, &request_params, create_surface_callback, ssync);175 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
176 wait_for_surface_create(ssync);176 wait_for_surface_create(ssync);
177177
178 request_params.width = 1600;178 request_params.width = 1600;
179 request_params.height = 1200;179 request_params.height = 1200;
180180
181 mir_surface_create(connection, &request_params, create_surface_callback, ssync+1);181 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+1);
182 wait_for_surface_create(ssync+1);182 wait_for_surface_create(ssync+1);
183183
184 MirSurfaceParameters response_params;184 MirSurfaceParameters response_params;
@@ -225,13 +225,13 @@
225 mir_buffer_usage_hardware225 mir_buffer_usage_hardware
226 };226 };
227227
228 mir_surface_create(connection, &request_params, create_surface_callback, ssync);228 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
229 wait_for_surface_create(ssync);229 wait_for_surface_create(ssync);
230230
231 request_params.width = 1600;231 request_params.width = 1600;
232 request_params.height = 1200;232 request_params.height = 1200;
233233
234 mir_surface_create(connection, &request_params, create_surface_callback, ssync+1);234 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+1);
235 wait_for_surface_create(ssync+1);235 wait_for_surface_create(ssync+1);
236236
237 EXPECT_NE(237 EXPECT_NE(
@@ -270,7 +270,7 @@
270 };270 };
271271
272 for (int i = 0; i != max_surface_count; ++i)272 for (int i = 0; i != max_surface_count; ++i)
273 mir_surface_create(connection, &request_params, create_surface_callback, ssync+i);273 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+i);
274274
275 for (int i = 0; i != max_surface_count; ++i)275 for (int i = 0; i != max_surface_count; ++i)
276 wait_for_surface_create(ssync+i);276 wait_for_surface_create(ssync+i);
277277
=== modified file 'tests/integration-tests/CMakeLists.txt'
--- tests/integration-tests/CMakeLists.txt 2013-03-29 22:30:35 +0000
+++ tests/integration-tests/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -12,9 +12,7 @@
12add_subdirectory(frontend/)12add_subdirectory(frontend/)
13add_subdirectory(shell/)13add_subdirectory(shell/)
14add_subdirectory(process/)14add_subdirectory(process/)
15if (NOT MIR_DISABLE_INPUT)
16add_subdirectory(input/)15add_subdirectory(input/)
17endif()
1816
19if (MIR_PLATFORM STREQUAL "android")17if (MIR_PLATFORM STREQUAL "android")
20 include_directories(${PROJECT_SOURCE_DIR}/include/accessory)18 include_directories(${PROJECT_SOURCE_DIR}/include/accessory)
2119
=== modified file 'tests/integration-tests/client/test_client_render.cpp'
--- tests/integration-tests/client/test_client_render.cpp 2013-03-29 16:51:35 +0000
+++ tests/integration-tests/client/test_client_render.cpp 2013-04-03 18:49:21 +0000
@@ -102,8 +102,8 @@
102 surface_parameters.width = test_width;102 surface_parameters.width = test_width;
103 surface_parameters.height = test_height;103 surface_parameters.height = test_height;
104 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;104 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
105 mir_wait_for(mir_surface_create( connection, &surface_parameters,105 mir_wait_for(mir_surface_create(connection, &surface_parameters,
106 &create_callback, &surface));106 NULL, &create_callback, &surface));
107107
108 auto graphics_region = std::make_shared<MirGraphicsRegion>();108 auto graphics_region = std::make_shared<MirGraphicsRegion>();
109 /* grab a buffer*/109 /* grab a buffer*/
@@ -143,8 +143,8 @@
143 surface_parameters.height = test_height;143 surface_parameters.height = test_height;
144 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;144 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
145145
146 mir_wait_for(mir_surface_create( connection, &surface_parameters,146 mir_wait_for(mir_surface_create(connection, &surface_parameters,
147 &create_callback, &surface));147 NULL, &create_callback, &surface));
148148
149 auto graphics_region = std::make_shared<MirGraphicsRegion>();149 auto graphics_region = std::make_shared<MirGraphicsRegion>();
150 mir_surface_get_graphics_region( surface, graphics_region.get());150 mir_surface_get_graphics_region( surface, graphics_region.get());
@@ -187,8 +187,8 @@
187 surface_parameters.height = test_height;187 surface_parameters.height = test_height;
188 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;188 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
189189
190 mir_wait_for(mir_surface_create( connection, &surface_parameters,190 mir_wait_for(mir_surface_create(connection, &surface_parameters,
191 &create_callback, &surface));191 NULL, &create_callback, &surface));
192192
193 int major, minor, n;193 int major, minor, n;
194 EGLDisplay disp;194 EGLDisplay disp;
@@ -249,8 +249,8 @@
249 surface_parameters.height = test_height;249 surface_parameters.height = test_height;
250 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;250 surface_parameters.pixel_format = mir_pixel_format_abgr_8888;
251251
252 mir_wait_for(mir_surface_create( connection, &surface_parameters,252 mir_wait_for(mir_surface_create(connection, &surface_parameters,
253 &create_callback, &surface));253 NULL, &create_callback, &surface));
254254
255 int major, minor, n;255 int major, minor, n;
256 EGLDisplay disp;256 EGLDisplay disp;
257257
=== modified file 'tests/integration-tests/input/android/test_android_cursor_listener.cpp'
--- tests/integration-tests/input/android/test_android_cursor_listener.cpp 2013-03-13 08:09:52 +0000
+++ tests/integration-tests/input/android/test_android_cursor_listener.cpp 2013-04-03 18:49:21 +0000
@@ -44,7 +44,6 @@
44namespace mtd = mir::test::doubles;44namespace mtd = mir::test::doubles;
4545
46using mtd::MockEventFilter;46using mtd::MockEventFilter;
47using mir::WaitCondition;
4847
49namespace48namespace
50{49{
@@ -100,7 +99,7 @@
100{99{
101 using namespace ::testing;100 using namespace ::testing;
102101
103 auto wait_condition = std::make_shared<WaitCondition>();102 auto wait_condition = std::make_shared<mt::WaitCondition>();
104103
105 static const float x = 100.f;104 static const float x = 100.f;
106 static const float y = 100.f;105 static const float y = 100.f;
@@ -109,7 +108,7 @@
109108
110 // The stack doesn't like shutting down while events are still moving through109 // The stack doesn't like shutting down while events are still moving through
111 EXPECT_CALL(event_filter, handles(_))110 EXPECT_CALL(event_filter, handles(_))
112 .WillOnce(ReturnFalseAndWakeUp(wait_condition));111 .WillOnce(mt::ReturnFalseAndWakeUp(wait_condition));
113112
114 fake_event_hub->synthesize_builtin_cursor_added();113 fake_event_hub->synthesize_builtin_cursor_added();
115 fake_event_hub->synthesize_device_scan_complete();114 fake_event_hub->synthesize_device_scan_complete();
116115
=== modified file 'tests/integration-tests/input/android/test_android_input_manager.cpp'
--- tests/integration-tests/input/android/test_android_input_manager.cpp 2013-04-02 16:40:08 +0000
+++ tests/integration-tests/input/android/test_android_input_manager.cpp 2013-04-03 18:49:21 +0000
@@ -53,7 +53,6 @@
53namespace mtd = mir::test::doubles;53namespace mtd = mir::test::doubles;
5454
55using mtd::MockEventFilter;55using mtd::MockEventFilter;
56using mir::WaitCondition;
5756
58namespace57namespace
59{58{
@@ -100,13 +99,13 @@
100{99{
101 using namespace ::testing;100 using namespace ::testing;
102101
103 WaitCondition wait_condition;102 mt::WaitCondition wait_condition;
104103
105 EXPECT_CALL(104 EXPECT_CALL(
106 event_filter,105 event_filter,
107 handles(mt::KeyDownEvent()))106 handles(mt::KeyDownEvent()))
108 .Times(1)107 .Times(1)
109 .WillOnce(ReturnFalseAndWakeUp(&wait_condition));108 .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
110109
111 fake_event_hub->synthesize_builtin_keyboard_added();110 fake_event_hub->synthesize_builtin_keyboard_added();
112 fake_event_hub->synthesize_device_scan_complete();111 fake_event_hub->synthesize_device_scan_complete();
@@ -121,13 +120,13 @@
121{120{
122 using namespace ::testing;121 using namespace ::testing;
123122
124 WaitCondition wait_condition;123 mt::WaitCondition wait_condition;
125124
126 EXPECT_CALL(125 EXPECT_CALL(
127 event_filter,126 event_filter,
128 handles(mt::ButtonDownEvent()))127 handles(mt::ButtonDownEvent()))
129 .Times(1)128 .Times(1)
130 .WillOnce(ReturnFalseAndWakeUp(&wait_condition));129 .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
131130
132 fake_event_hub->synthesize_builtin_cursor_added();131 fake_event_hub->synthesize_builtin_cursor_added();
133 fake_event_hub->synthesize_device_scan_complete();132 fake_event_hub->synthesize_device_scan_complete();
@@ -141,7 +140,7 @@
141{140{
142 using namespace ::testing;141 using namespace ::testing;
143142
144 WaitCondition wait_condition;143 mt::WaitCondition wait_condition;
145144
146 // We get absolute motion events since we have a pointer controller.145 // We get absolute motion events since we have a pointer controller.
147 {146 {
@@ -152,7 +151,7 @@
152 .WillOnce(Return(false));151 .WillOnce(Return(false));
153 EXPECT_CALL(event_filter,152 EXPECT_CALL(event_filter,
154 handles(mt::MotionEvent(200, 100)))153 handles(mt::MotionEvent(200, 100)))
155 .WillOnce(ReturnFalseAndWakeUp(&wait_condition));154 .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
156 }155 }
157156
158 fake_event_hub->synthesize_builtin_cursor_added();157 fake_event_hub->synthesize_builtin_cursor_added();
@@ -253,7 +252,7 @@
253{252{
254 using namespace ::testing;253 using namespace ::testing;
255254
256 WaitCondition wait_condition;255 mt::WaitCondition wait_condition;
257256
258 mtd::StubSessionTarget session;257 mtd::StubSessionTarget session;
259 mtd::StubSurfaceTarget surface(test_input_fd);258 mtd::StubSurfaceTarget surface(test_input_fd);
@@ -261,7 +260,7 @@
261 EXPECT_CALL(event_filter, handles(_)).Times(1).WillOnce(Return(false));260 EXPECT_CALL(event_filter, handles(_)).Times(1).WillOnce(Return(false));
262 // We return -1 here to skip publishing of the event (to an unconnected test socket!).261 // We return -1 here to skip publishing of the event (to an unconnected test socket!).
263 EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(test_input_fd), _, _))262 EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(test_input_fd), _, _))
264 .Times(1).WillOnce(DoAll(WakeUp(&wait_condition), Return(-1)));263 .Times(1).WillOnce(DoAll(mt::WakeUp(&wait_condition), Return(-1)));
265264
266 input_manager->set_input_focus_to(mt::fake_shared(session), mt::fake_shared(surface));265 input_manager->set_input_focus_to(mt::fake_shared(session), mt::fake_shared(surface));
267266
268267
=== modified file 'tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp'
--- tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp 2013-04-02 16:40:08 +0000
+++ tests/integration-tests/input/android/test_fake_event_hub_to_event_filter.cpp 2013-04-03 18:49:21 +0000
@@ -95,16 +95,15 @@
95}95}
9696
97using mir::FakeEventHubSetup;97using mir::FakeEventHubSetup;
98using mir::WaitCondition;
9998
100TEST_F(FakeEventHubSetup, fake_event_hub_dispatches_to_filter)99TEST_F(FakeEventHubSetup, fake_event_hub_dispatches_to_filter)
101{100{
102 using namespace ::testing;101 using namespace ::testing;
103102
104 mir::WaitCondition wait_condition;103 mt::WaitCondition wait_condition;
105104
106 EXPECT_CALL(event_filter, handles(mt::KeyDownEvent())).Times(1)105 EXPECT_CALL(event_filter, handles(mt::KeyDownEvent())).Times(1)
107 .WillOnce(ReturnFalseAndWakeUp(&wait_condition));106 .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition));
108107
109 event_hub->synthesize_builtin_keyboard_added();108 event_hub->synthesize_builtin_keyboard_added();
110 event_hub->synthesize_device_scan_complete();109 event_hub->synthesize_device_scan_complete();
111110
=== modified file 'tests/integration-tests/test_error_reporting.cpp'
--- tests/integration-tests/test_error_reporting.cpp 2013-03-22 10:34:16 +0000
+++ tests/integration-tests/test_error_reporting.cpp 2013-04-03 18:49:21 +0000
@@ -238,7 +238,7 @@
238 mir_buffer_usage_hardware238 mir_buffer_usage_hardware
239 };239 };
240240
241 mir_surface_create(connection, &request_params, create_surface_callback, ssync);241 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
242242
243 wait_for_surface_create(ssync);243 wait_for_surface_create(ssync);
244244
245245
=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
--- tests/integration-tests/test_surfaceloop.cpp 2013-03-25 10:18:17 +0000
+++ tests/integration-tests/test_surfaceloop.cpp 2013-04-03 18:49:21 +0000
@@ -286,7 +286,7 @@
286 mir_buffer_usage_hardware286 mir_buffer_usage_hardware
287 };287 };
288288
289 mir_surface_create(connection, &request_params, create_surface_callback, ssync);289 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
290290
291 wait_for_surface_create(ssync);291 wait_for_surface_create(ssync);
292292
@@ -388,7 +388,7 @@
388 mir_pixel_format_abgr_8888,388 mir_pixel_format_abgr_8888,
389 mir_buffer_usage_hardware389 mir_buffer_usage_hardware
390 };390 };
391 mir_surface_create(connection, &request_params, create_surface_callback, ssync);391 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync);
392392
393 wait_for_surface_create(ssync);393 wait_for_surface_create(ssync);
394394
@@ -522,7 +522,7 @@
522 };522 };
523523
524 for (int i = 0; i != max_surface_count; ++i)524 for (int i = 0; i != max_surface_count; ++i)
525 mir_surface_create(connection, &request_params, create_surface_callback, ssync+i);525 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+i);
526526
527 for (int i = 0; i != max_surface_count; ++i)527 for (int i = 0; i != max_surface_count; ++i)
528 wait_for_surface_create(ssync+i);528 wait_for_surface_create(ssync+i);
@@ -571,7 +571,7 @@
571 };571 };
572572
573 for (int i = 0; i != max_surface_count; ++i)573 for (int i = 0; i != max_surface_count; ++i)
574 mir_surface_create(connection, &request_params, create_surface_callback, ssync+i);574 mir_surface_create(connection, &request_params, NULL, create_surface_callback, ssync+i);
575575
576 for (int i = 0; i != max_surface_count; ++i)576 for (int i = 0; i != max_surface_count; ++i)
577 wait_for_surface_create(ssync+i);577 wait_for_surface_create(ssync+i);
578578
=== modified file 'tests/mir_test_doubles/CMakeLists.txt'
--- tests/mir_test_doubles/CMakeLists.txt 2013-03-28 09:50:09 +0000
+++ tests/mir_test_doubles/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -10,12 +10,10 @@
10 event_factory.cpp10 event_factory.cpp
11)11)
1212
13if (NOT MIR_DISABLE_INPUT)
14list(APPEND TEST_UTILS_SRCS13list(APPEND TEST_UTILS_SRCS
15 fake_event_hub.cpp14 fake_event_hub.cpp
16 fake_event_hub_input_configuration.cpp15 fake_event_hub_input_configuration.cpp
17)16)
18endif()
1917
20list(APPEND TEST_UTILS_SRCS18list(APPEND TEST_UTILS_SRCS
21 test_protobuf_socket_server.cpp19 test_protobuf_socket_server.cpp
2220
=== modified file 'tests/unit-tests/CMakeLists.txt'
--- tests/unit-tests/CMakeLists.txt 2013-03-29 22:30:35 +0000
+++ tests/unit-tests/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -11,11 +11,8 @@
11add_subdirectory(shell/)11add_subdirectory(shell/)
12add_subdirectory(geometry/)12add_subdirectory(geometry/)
13add_subdirectory(graphics/)13add_subdirectory(graphics/)
14#TODO stubbed out to run tests on emulator
15if (NOT MIR_DISABLE_INPUT)
16add_subdirectory(input/)14add_subdirectory(input/)
17add_subdirectory(android_input/)15add_subdirectory(android_input/)
18endif()
19add_subdirectory(surfaces/)16add_subdirectory(surfaces/)
20add_subdirectory(draw/)17add_subdirectory(draw/)
2118
2219
=== modified file 'tests/unit-tests/client/CMakeLists.txt'
--- tests/unit-tests/client/CMakeLists.txt 2013-03-24 23:33:49 +0000
+++ tests/unit-tests/client/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -16,4 +16,8 @@
16 add_subdirectory("gbm")16 add_subdirectory("gbm")
17endif()17endif()
1818
19if (NOT MIR_DISABLE_INPUT)
20add_subdirectory("input")
21endif()
22
19set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE)23set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE)
2024
=== added directory 'tests/unit-tests/client/input'
=== added file 'tests/unit-tests/client/input/CMakeLists.txt'
--- tests/unit-tests/client/input/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/client/input/CMakeLists.txt 2013-04-03 18:49:21 +0000
@@ -0,0 +1,9 @@
1list(APPEND UNIT_TEST_SOURCES
2 ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_receiver_thread.cpp
3 ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_receiver.cpp
4)
5
6set(
7 UNIT_TEST_SOURCES
8 ${UNIT_TEST_SOURCES}
9 PARENT_SCOPE)
010
=== added file 'tests/unit-tests/client/input/test_android_input_receiver.cpp'
--- tests/unit-tests/client/input/test_android_input_receiver.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/client/input/test_android_input_receiver.cpp 2013-04-03 18:49:21 +0000
@@ -0,0 +1,198 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "src/client/input/android_input_receiver.h"
20#include "mir_toolkit/input/event.h"
21
22#include <androidfw/InputTransport.h>
23
24#include <gmock/gmock.h>
25#include <gtest/gtest.h>
26
27#include <unistd.h>
28#include <memory>
29
30namespace mclia = mir::client::input::android;
31
32namespace droidinput = android;
33
34namespace
35{
36
37class TestingInputProducer
38{
39public:
40 TestingInputProducer(droidinput::sp<droidinput::InputChannel> input_channel) :
41 input_publisher(std::make_shared<droidinput::InputPublisher>(input_channel)),
42 incrementing_seq_id(1), // Sequence id must be > 0 or publisher will reject
43 testing_key_event_key_code(13)
44 {
45 }
46
47 // The input publisher does not care about event semantics so we only highlight
48 // a few fields for transport verification
49 void produce_a_key_event()
50 {
51 input_publisher->publishKeyEvent(
52 incrementing_seq_id,
53 filler_device_id,
54 0 /* source */,
55 0 /* action */,
56 0 /* flags */,
57 testing_key_event_key_code,
58 0 /* scan_code */,
59 0 /* meta_state */,
60 0 /* repeat_count */,
61 0 /* down_time */,
62 0 /* event_time */);
63 }
64 void produce_a_motion_event()
65 {
66 droidinput::PointerProperties filler_pointer_properties;
67 droidinput::PointerCoords filler_pointer_coordinates;
68
69 memset(&filler_pointer_properties, 0, sizeof(droidinput::PointerProperties));
70 memset(&filler_pointer_coordinates, 0, sizeof(droidinput::PointerCoords));
71
72 input_publisher->publishMotionEvent(
73 incrementing_seq_id,
74 filler_device_id,
75 0 /* source */,
76 motion_event_action_flags,
77 0 /* flags */,
78 0 /* edge_flags */,
79 0 /* meta_state */,
80 0 /* button_state */,
81 0 /* x_offset */, 0 /* y_offset */,
82 0 /* x_precision */, 0 /* y_precision */,
83 0 /* down_time */,
84 0 /* event_time */,
85 default_pointer_count,
86 &filler_pointer_properties,
87 &filler_pointer_coordinates);
88 }
89
90 bool must_receive_handled_signal()
91 {
92 uint32_t seq;
93 bool handled;
94
95 auto status = input_publisher->receiveFinishedSignal(&seq, &handled);
96 return (status == droidinput::OK) && handled;
97 }
98
99 std::shared_ptr<droidinput::InputPublisher> input_publisher;
100
101 int incrementing_seq_id;
102 int32_t testing_key_event_key_code;
103
104 // Some default values
105 // device_id must be > 0 or input publisher will reject
106 static const int32_t filler_device_id = 1;
107 // AMOTION_EVENT_ACTION_MOVE is necessary to engage batching behavior
108 static const int32_t motion_event_action_flags = AMOTION_EVENT_ACTION_MOVE;
109 // We have to have at least 1 pointer or the publisher will fail to marshal a motion event
110 static const int32_t default_pointer_count = 1;
111};
112
113class AndroidInputReceiverSetup : public testing::Test
114{
115public:
116 AndroidInputReceiverSetup()
117 {
118 droidinput::String8 const testing_channel_name = droidinput::String8("Terrapin");
119 auto status = droidinput::InputChannel::openInputChannelPair(testing_channel_name,
120 android_client_channel,
121 android_server_channel);
122
123 EXPECT_EQ(droidinput::OK, status);
124 }
125
126 void flush_channels()
127 {
128 fsync(android_server_channel->getFd());
129 fsync(android_client_channel->getFd());
130 }
131
132 droidinput::sp<droidinput::InputChannel> android_client_channel;
133 droidinput::sp<droidinput::InputChannel> android_server_channel;
134
135 static std::chrono::milliseconds const next_event_timeout;
136};
137
138std::chrono::milliseconds const AndroidInputReceiverSetup::next_event_timeout(1000);
139
140}
141
142TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd)
143{
144 mclia::InputReceiver receiver(android_client_channel);
145
146 EXPECT_EQ(android_client_channel->getFd(), receiver.fd());
147}
148
149TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events)
150{
151 mclia::InputReceiver receiver(android_client_channel);
152 TestingInputProducer producer(android_server_channel);
153
154 producer.produce_a_key_event();
155
156 flush_channels();
157
158 MirEvent ev;
159 EXPECT_EQ(true, receiver.next_event(next_event_timeout, ev));
160 EXPECT_EQ(MIR_INPUT_EVENT_TYPE_KEY, ev.type);
161 EXPECT_EQ(producer.testing_key_event_key_code, ev.details.key.key_code);
162}
163
164TEST_F(AndroidInputReceiverSetup, receiver_handles_events)
165{
166 mclia::InputReceiver receiver(android_client_channel);
167 TestingInputProducer producer(android_server_channel);
168
169 producer.produce_a_key_event();
170 flush_channels();
171
172 MirEvent ev;
173 EXPECT_EQ(true, receiver.next_event(next_event_timeout, ev));
174
175 flush_channels();
176
177 EXPECT_TRUE (producer.must_receive_handled_signal());
178}
179
180TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events)
181{
182 mclia::InputReceiver receiver(android_client_channel);
183 TestingInputProducer producer(android_server_channel);
184
185 // Produce 3 motion events before client handles any.
186 producer.produce_a_motion_event();
187 producer.produce_a_motion_event();
188 producer.produce_a_motion_event();
189
190 flush_channels();
191
192 MirEvent ev;
193 // Handle all three events as a batched event
194 EXPECT_TRUE(receiver.next_event(next_event_timeout, ev));
195 // Now there should be no events
196 EXPECT_FALSE(receiver.next_event(std::chrono::milliseconds(1), ev)); // Minimal timeout needed for valgrind
197}
198
0199
=== added file 'tests/unit-tests/client/input/test_android_input_receiver_thread.cpp'
--- tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/client/input/test_android_input_receiver_thread.cpp 2013-04-03 18:49:21 +0000
@@ -0,0 +1,152 @@
1/*
2 * Copyright © 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */
18
19#include "src/client/input/android_input_receiver_thread.h"
20#include "src/client/input/android_input_receiver.h"
21
22#include "mir_toolkit/mir_client_library.h"
23
24#include <gtest/gtest.h>
25#include <gmock/gmock.h>
26
27#include <androidfw/InputTransport.h>
28
29#include <atomic>
30
31#include <fcntl.h>
32
33namespace mclia = mir::client::input::android;
34
35namespace
36{
37
38struct MockEventHandler
39{
40 MOCK_METHOD1(handle_event, void(MirEvent*));
41};
42
43struct MockInputReceiver : public mclia::InputReceiver
44{
45 MockInputReceiver(int fd)
46 : InputReceiver(fd)
47 {
48 }
49 MOCK_METHOD1(next_event, bool(MirEvent &));
50};
51
52struct AndroidInputReceiverThreadSetup : public testing::Test
53{
54 AndroidInputReceiverThreadSetup()
55 {
56 test_receiver_fd = open("/dev/null", O_APPEND);
57 input_receiver = std::make_shared<MockInputReceiver>(test_receiver_fd);
58 }
59 virtual ~AndroidInputReceiverThreadSetup()
60 {
61 close(test_receiver_fd);
62 }
63
64 int test_receiver_fd;
65 std::shared_ptr<MockInputReceiver> input_receiver;
66};
67
68ACTION_P(StopThread, thread)
69{
70 thread->stop();
71// thread->join();
72}
73
74}
75
76TEST_F(AndroidInputReceiverThreadSetup, reads_events_until_stopped)
77{
78 using namespace ::testing;
79
80 mclia::InputReceiverThread input_thread(input_receiver,
81 std::function<void(MirEvent*)>());
82 {
83 InSequence seq;
84 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false));
85 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false));
86 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(false)));
87 }
88 input_thread.start();
89 input_thread.join();
90}
91
92TEST_F(AndroidInputReceiverThreadSetup, receives_and_dispatches_available_events_when_ready)
93{
94 using namespace ::testing;
95 MockEventHandler mock_handler;
96
97 struct InputDelegate
98 {
99 InputDelegate(MockEventHandler& handler)
100 : handler(handler) {}
101 void operator()(MirEvent* ev)
102 {
103 handler.handle_event(ev);
104 }
105 MockEventHandler &handler;
106 } input_delegate(mock_handler);
107
108 mclia::InputReceiverThread input_thread(input_receiver, input_delegate);
109 {
110 InSequence seq;
111
112 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(true));
113 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false));
114 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(true)));
115 }
116 EXPECT_CALL(mock_handler, handle_event(_)).Times(2);
117
118 input_thread.start();
119 input_thread.join();
120}
121
122TEST_F(AndroidInputReceiverThreadSetup, input_callback_invoked_from_thread)
123{
124 using namespace ::testing;
125 MockEventHandler mock_handler;
126 std::atomic<bool> handled;
127
128 handled = false;
129
130 struct InputDelegate
131 {
132 InputDelegate(std::atomic<bool> &handled)
133 : handled(handled) {}
134 void operator()(MirEvent* /*ev*/)
135 {
136 handled = true;
137 }
138 std::atomic<bool> &handled;
139 } input_delegate(handled);
140
141 mclia::InputReceiverThread input_thread(input_receiver, input_delegate);
142 {
143 InSequence seq;
144
145 EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(true)));
146 }
147
148 input_thread.start();
149 while (handled == false) { } // We would block forever here were delivery not threaded
150 input_thread.join();
151}
152
0153
=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
--- tests/unit-tests/client/test_client_mir_surface.cpp 2013-03-26 09:37:47 +0000
+++ tests/unit-tests/client/test_client_mir_surface.cpp 2013-04-03 18:49:21 +0000
@@ -20,25 +20,30 @@
20#include "mir_toolkit/mir_client_library.h"20#include "mir_toolkit/mir_client_library.h"
21#include "src/client/mir_logger.h"21#include "src/client/mir_logger.h"
22#include "src/client/client_buffer.h"22#include "src/client/client_buffer.h"
23#include "src/client/client_buffer_depository.h"
24#include "src/client/client_buffer_factory.h"23#include "src/client/client_buffer_factory.h"
25#include "src/client/client_platform.h"24#include "src/client/client_platform.h"
26#include "src/client/client_platform_factory.h"25#include "src/client/client_platform_factory.h"
27#include "src/client/mir_surface.h"26#include "src/client/mir_surface.h"
28#include "src/client/mir_connection.h"27#include "src/client/mir_connection.h"
28#include "src/client/input/input_platform.h"
29#include "src/client/input/input_receiver_thread.h"
29#include "mir/frontend/resource_cache.h"30#include "mir/frontend/resource_cache.h"
3031
31#include "mir_test/test_protobuf_server.h"32#include "mir_test/test_protobuf_server.h"
32#include "mir_test/stub_server_tool.h"33#include "mir_test/stub_server_tool.h"
33#include "mir_test/test_protobuf_client.h"34#include "mir_test/test_protobuf_client.h"
34#include "mir_test/gmock_fixes.h"35#include "mir_test/gmock_fixes.h"
36#include "mir_test/fake_shared.h"
3537
36#include <cstring>38#include <cstring>
3739
38#include <gtest/gtest.h>40#include <gtest/gtest.h>
39#include <gmock/gmock.h>41#include <gmock/gmock.h>
4042
43#include <fcntl.h>
44
41namespace mcl = mir::client;45namespace mcl = mir::client;
46namespace mcli = mcl::input;
42namespace mp = mir::protobuf;47namespace mp = mir::protobuf;
43namespace geom = mir::geometry;48namespace geom = mir::geometry;
4449
@@ -52,10 +57,17 @@
52 MockServerPackageGenerator()57 MockServerPackageGenerator()
53 : global_buffer_id(0)58 : global_buffer_id(0)
54 {59 {
55 generate_unique_buffer();
56 width_sent = 891;60 width_sent = 891;
57 height_sent = 458;61 height_sent = 458;
58 pf_sent = mir_pixel_format_abgr_8888;62 pf_sent = mir_pixel_format_abgr_8888;
63
64 input_fd = open("/dev/null", O_APPEND);
65 }
66 ~MockServerPackageGenerator()
67 {
68 close(input_fd);
69 for (int i = 0; i < server_package.fd_items; i++)
70 close(server_package.fd[0]);
59 }71 }
6072
61 void create_surface(google::protobuf::RpcController*,73 void create_surface(google::protobuf::RpcController*,
@@ -86,8 +98,12 @@
86 int num_fd = 2, num_data = 8;98 int num_fd = 2, num_data = 8;
87 for (auto i=0; i<num_fd; i++)99 for (auto i=0; i<num_fd; i++)
88 {100 {
89 server_package.fd[i] = global_buffer_id * i;101 if (server_package.fd[i])
102 close(server_package.fd[i]);
103 server_package.fd[i] = open("/dev/null", O_APPEND);
90 }104 }
105 server_package.fd_items = num_fd;
106 server_package.data_items = num_data;
91 for (auto i=0; i<num_data; i++)107 for (auto i=0; i<num_data; i++)
92 {108 {
93 server_package.data[i] = (global_buffer_id + i) * 2;109 server_package.data[i] = (global_buffer_id + i) * 2;
@@ -100,16 +116,20 @@
100 int width_sent;116 int width_sent;
101 int height_sent;117 int height_sent;
102 int pf_sent;118 int pf_sent;
119
120 int input_fd;
103121
104 private:122 private:
105 int global_buffer_id;123 int global_buffer_id;
106124
107 void create_buffer_response(mir::protobuf::Buffer* response)125 void create_buffer_response(mir::protobuf::Buffer* response)
108 {126 {
127 generate_unique_buffer();
128
109 response->set_buffer_id(global_buffer_id);129 response->set_buffer_id(global_buffer_id);
110130
111 /* assemble buffers */131 /* assemble buffers */
112 response->set_fds_on_side_channel(1);132 response->set_fds_on_side_channel(server_package.fd_items);
113 for (int i=0; i< server_package.data_items; i++)133 for (int i=0; i< server_package.data_items; i++)
114 {134 {
115 response->add_data(server_package.data[i]);135 response->add_data(server_package.data[i]);
@@ -120,16 +140,18 @@
120 }140 }
121141
122 response->set_stride(server_package.stride);142 response->set_stride(server_package.stride);
123
124 generate_unique_buffer();
125 }143 }
126144
127 void create_surface_response(mir::protobuf::Surface* response)145 void create_surface_response(mir::protobuf::Surface* response)
128 {146 {
147 response->set_fds_on_side_channel(1);
148
129 response->mutable_id()->set_value(2);149 response->mutable_id()->set_value(2);
130 response->set_width(width_sent);150 response->set_width(width_sent);
131 response->set_height(height_sent);151 response->set_height(height_sent);
132 response->set_pixel_format(pf_sent);152 response->set_pixel_format(pf_sent);
153 response->add_fd(input_fd);
154
133 create_buffer_response(response->mutable_buffer());155 create_buffer_response(response->mutable_buffer());
134 }156 }
135};157};
@@ -207,6 +229,26 @@
207 }229 }
208};230};
209231
232struct StubClientInputPlatform : public mcli::InputPlatform
233{
234 std::shared_ptr<mcli::InputReceiverThread> create_input_thread(int /* fd */, std::function<void(MirEvent*)> const& /* callback */)
235 {
236 return std::shared_ptr<mcli::InputReceiverThread>();
237 }
238};
239
240struct MockClientInputPlatform : public mcli::InputPlatform
241{
242 MOCK_METHOD2(create_input_thread, std::shared_ptr<mcli::InputReceiverThread>(int, std::function<void(MirEvent*)> const&));
243};
244
245struct MockInputReceiverThread : public mcli::InputReceiverThread
246{
247 MOCK_METHOD0(start, void());
248 MOCK_METHOD0(stop, void());
249 MOCK_METHOD0(join, void());
250};
251
210}252}
211}253}
212254
@@ -232,6 +274,8 @@
232274
233 mock_buffer_factory = std::make_shared<mt::MockClientBufferFactory>();275 mock_buffer_factory = std::make_shared<mt::MockClientBufferFactory>();
234276
277 input_platform = std::make_shared<mt::StubClientInputPlatform>();
278
235 params = MirSurfaceParameters{"test", 33, 45, mir_pixel_format_abgr_8888,279 params = MirSurfaceParameters{"test", 33, 45, mir_pixel_format_abgr_8888,
236 mir_buffer_usage_hardware};280 mir_buffer_usage_hardware};
237281
@@ -261,6 +305,7 @@
261305
262 MirSurfaceParameters params;306 MirSurfaceParameters params;
263 std::shared_ptr<mt::MockClientBufferFactory> mock_buffer_factory;307 std::shared_ptr<mt::MockClientBufferFactory> mock_buffer_factory;
308 std::shared_ptr<mt::StubClientInputPlatform> input_platform;
264309
265 mir::protobuf::Connection response;310 mir::protobuf::Connection response;
266 mir::protobuf::ConnectParameters connect_parameters;311 mir::protobuf::ConnectParameters connect_parameters;
@@ -282,13 +327,7 @@
282 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))327 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))
283 .Times(1);328 .Times(1);
284329
285 auto surface = std::make_shared<MirSurface> (connection.get(),330 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
286 *client_comm_channel,
287 logger,
288 mock_buffer_factory,
289 params,
290 &empty_callback,
291 nullptr);
292331
293 auto wait_handle = surface->get_create_wait_handle();332 auto wait_handle = surface->get_create_wait_handle();
294 wait_handle->wait_for_result();333 wait_handle->wait_for_result();
@@ -306,20 +345,14 @@
306 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))345 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))
307 .Times(1);346 .Times(1);
308347
309 auto surface = std::make_shared<MirSurface> (connection.get(),348 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
310 *client_comm_channel,
311 logger,
312 mock_buffer_factory,
313 params,
314 &empty_callback,
315 nullptr);
316349
317 auto wait_handle = surface->get_create_wait_handle();350 auto wait_handle = surface->get_create_wait_handle();
318 wait_handle->wait_for_result();351 wait_handle->wait_for_result();
319352
320 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))353 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_))
321 .Times(1);354 .Times(1);
322 auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, (void*) NULL);355 auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, nullptr);
323 buffer_wait_handle->wait_for_result();356 buffer_wait_handle->wait_for_result();
324}357}
325358
@@ -328,12 +361,11 @@
328 // Can't simply use memcmp() on the whole struct because age is not sent over the wire361 // Can't simply use memcmp() on the whole struct because age is not sent over the wire
329 if (package.data_items != arg.data_items)362 if (package.data_items != arg.data_items)
330 return false;363 return false;
364 // Note we can not compare the fd's directly as they may change when being sent over the wire.
331 if (package.fd_items != arg.fd_items)365 if (package.fd_items != arg.fd_items)
332 return false;366 return false;
333 if (memcmp(package.data, arg.data, sizeof(package.data[0]) * package.data_items))367 if (memcmp(package.data, arg.data, sizeof(package.data[0]) * package.data_items))
334 return false;368 return false;
335 if (memcmp(package.fd, arg.fd, sizeof(package.fd[0]) * package.fd_items))
336 return false;
337 if (package.stride != arg.stride)369 if (package.stride != arg.stride)
338 return false;370 return false;
339 return true;371 return true;
@@ -349,13 +381,8 @@
349 .WillOnce(DoAll(SaveArg<0>(&submitted_package),381 .WillOnce(DoAll(SaveArg<0>(&submitted_package),
350 Return(mock_buffer_factory->emptybuffer)));382 Return(mock_buffer_factory->emptybuffer)));
351383
352 auto surface = std::make_shared<MirSurface> (connection.get(),384 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
353 *client_comm_channel,385
354 logger,
355 mock_buffer_factory,
356 params,
357 &empty_callback,
358 nullptr);
359 auto wait_handle = surface->get_create_wait_handle();386 auto wait_handle = surface->get_create_wait_handle();
360 wait_handle->wait_for_result();387 wait_handle->wait_for_result();
361388
@@ -375,13 +402,8 @@
375 .WillOnce(DoAll(SaveArg<1>(&sz),402 .WillOnce(DoAll(SaveArg<1>(&sz),
376 Return(mock_buffer_factory->emptybuffer)));403 Return(mock_buffer_factory->emptybuffer)));
377404
378 auto surface = std::make_shared<MirSurface> (connection.get(),405 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
379 *client_comm_channel,406
380 logger,
381 mock_buffer_factory,
382 params,
383 &empty_callback,
384 nullptr);
385 auto wait_handle = surface->get_create_wait_handle();407 auto wait_handle = surface->get_create_wait_handle();
386 wait_handle->wait_for_result();408 wait_handle->wait_for_result();
387409
@@ -400,13 +422,8 @@
400 .WillOnce(DoAll(SaveArg<1>(&sz),422 .WillOnce(DoAll(SaveArg<1>(&sz),
401 Return(mock_buffer_factory->emptybuffer)));423 Return(mock_buffer_factory->emptybuffer)));
402424
403 auto surface = std::make_shared<MirSurface> (connection.get(),425 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
404 *client_comm_channel,426
405 logger,
406 mock_buffer_factory,
407 params,
408 &empty_callback,
409 nullptr);
410 auto wait_handle = surface->get_create_wait_handle();427 auto wait_handle = surface->get_create_wait_handle();
411 wait_handle->wait_for_result();428 wait_handle->wait_for_result();
412429
@@ -425,13 +442,7 @@
425 .WillOnce(DoAll(SaveArg<2>(&pf),442 .WillOnce(DoAll(SaveArg<2>(&pf),
426 Return(mock_buffer_factory->emptybuffer)));443 Return(mock_buffer_factory->emptybuffer)));
427444
428 auto surface = std::make_shared<MirSurface> (connection.get(),445 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger, mock_buffer_factory, input_platform, params, nullptr, &empty_callback, nullptr);
429 *client_comm_channel,
430 logger,
431 mock_buffer_factory,
432 params,
433 &empty_callback,
434 nullptr);
435446
436 auto wait_handle = surface->get_create_wait_handle();447 auto wait_handle = surface->get_create_wait_handle();
437 wait_handle->wait_for_result();448 wait_handle->wait_for_result();
@@ -439,6 +450,46 @@
439 EXPECT_EQ(pf, geom::PixelFormat::abgr_8888);450 EXPECT_EQ(pf, geom::PixelFormat::abgr_8888);
440}451}
441452
453
454
455namespace
456{
457static void null_event_callback(MirSurface*, MirEvent*, void*)
458{
459}
460}
461
462TEST_F(MirClientSurfaceTest, input_fd_used_to_create_input_thread_when_delegate_specified)
463{
464 using namespace ::testing;
465
466 auto mock_input_platform = std::make_shared<mt::MockClientInputPlatform>();
467 auto mock_input_thread = std::make_shared<mt::MockInputReceiverThread>();
468 MirEventDelegate delegate = {null_event_callback, nullptr};
469
470 EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)).Times(2);
471
472 EXPECT_CALL(*mock_input_platform, create_input_thread(_, _)).Times(1)
473 .WillOnce(Return(mock_input_thread));
474 EXPECT_CALL(*mock_input_thread, start()).Times(1);
475 EXPECT_CALL(*mock_input_thread, stop()).Times(1);
476
477 {
478 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger,
479 mock_buffer_factory, mock_input_platform, params, &delegate, &empty_callback, nullptr);
480 auto wait_handle = surface->get_create_wait_handle();
481 wait_handle->wait_for_result();
482 }
483
484 {
485 // This surface should not trigger a call to the input platform as no input delegate is specified.
486 auto surface = std::make_shared<MirSurface> (connection.get(), *client_comm_channel, logger,
487 mock_buffer_factory, mock_input_platform, params, nullptr, &empty_callback, nullptr);
488 auto wait_handle = surface->get_create_wait_handle();
489 wait_handle->wait_for_result();
490 }
491}
492
442TEST_F(MirClientSurfaceTest, get_buffer_returns_last_received_buffer_package)493TEST_F(MirClientSurfaceTest, get_buffer_returns_last_received_buffer_package)
443{494{
444 using namespace testing;495 using namespace testing;
@@ -450,7 +501,9 @@
450 *client_comm_channel,501 *client_comm_channel,
451 logger,502 logger,
452 mock_buffer_factory,503 mock_buffer_factory,
504 input_platform,
453 params,505 params,
506 nullptr,
454 &empty_callback,507 &empty_callback,
455 nullptr);508 nullptr);
456 auto wait_handle = surface->get_create_wait_handle();509 auto wait_handle = surface->get_create_wait_handle();
@@ -478,7 +531,9 @@
478 *client_comm_channel,531 *client_comm_channel,
479 logger,532 logger,
480 mock_buffer_factory,533 mock_buffer_factory,
534 input_platform,
481 params,535 params,
536 nullptr,
482 &empty_callback,537 &empty_callback,
483 nullptr);538 nullptr);
484 surface->get_create_wait_handle()->wait_for_result();539 surface->get_create_wait_handle()->wait_for_result();
485540
=== modified file 'tests/unit-tests/input/android/test_android_input_application_handle.cpp'
--- tests/unit-tests/input/android/test_android_input_application_handle.cpp 2013-03-29 16:51:35 +0000
+++ tests/unit-tests/input/android/test_android_input_application_handle.cpp 2013-04-03 18:49:21 +0000
@@ -20,8 +20,6 @@
2020
21#include "mir/input/session_target.h"21#include "mir/input/session_target.h"
2222
23#include "mir_test/fake_shared.h"
24
25#include <gtest/gtest.h>23#include <gtest/gtest.h>
26#include <gmock/gmock.h>24#include <gmock/gmock.h>
2725
@@ -29,7 +27,6 @@
2927
30namespace mi = mir::input;28namespace mi = mir::input;
31namespace mia = mi::android;29namespace mia = mi::android;
32namespace mt = mir::test;
3330
34namespace31namespace
35{32{
@@ -44,15 +41,30 @@
44{41{
45 using namespace ::testing;42 using namespace ::testing;
46 std::string const testing_session_name = "Cats";43 std::string const testing_session_name = "Cats";
47 MockSessionHandle session;44 auto session = std::make_shared<MockSessionHandle>();
4845
49 EXPECT_CALL(session, name()).Times(AtLeast(1))46 EXPECT_CALL(*session, name()).Times(AtLeast(1))
50 .WillRepeatedly(Return(testing_session_name));47 .WillRepeatedly(Return(testing_session_name));
51 mia::InputApplicationHandle application_handle(mt::fake_shared(session));48 mia::InputApplicationHandle application_handle(session);
52 EXPECT_TRUE(application_handle.updateInfo());49 EXPECT_TRUE(application_handle.updateInfo());
53 auto info = application_handle.getInfo();50 auto info = application_handle.getInfo();
54 EXPECT_EQ(INT_MAX, info->dispatchingTimeout);51 EXPECT_EQ(INT_MAX, info->dispatchingTimeout);
55 EXPECT_EQ(droidinput::String8(testing_session_name.c_str()), info->name);52 EXPECT_EQ(droidinput::String8(testing_session_name.c_str()), info->name);
56}53}
5754
55TEST(AndroidInputApplicationHandle, does_not_own_session)
56{
57 using namespace ::testing;
58 std::string const testing_session_name = "Let it Grow";
59
60 auto session = std::make_shared<MockSessionHandle>();
61 EXPECT_CALL(*session, name()).Times(AtLeast(1))
62 .WillRepeatedly(Return(testing_session_name));
63
64 mia::InputApplicationHandle application_handle(session);
65 EXPECT_TRUE(application_handle.updateInfo());
66 session.reset();
67 EXPECT_FALSE(application_handle.updateInfo());
68
69}
5870
5971
=== modified file 'tests/unit-tests/input/android/test_android_input_lexicon.cpp'
--- tests/unit-tests/input/android/test_android_input_lexicon.cpp 2013-03-13 08:09:52 +0000
+++ tests/unit-tests/input/android/test_android_input_lexicon.cpp 2013-04-03 18:49:21 +0000
@@ -15,8 +15,8 @@
15 *15 *
16 * Authored by: Robert Carr <robert.carr@canonical.com>16 * Authored by: Robert Carr <robert.carr@canonical.com>
17 */17 */
18#include "src/server/input/android/android_input_lexicon.h"18
19// Is this the right place for this header? Will eventually be included by clients.19#include "mir/input/android/android_input_lexicon.h"
20#include "mir_toolkit/input/event.h"20#include "mir_toolkit/input/event.h"
2121
22#include <androidfw/Input.h>22#include <androidfw/Input.h>
@@ -25,7 +25,7 @@
25#include <gmock/gmock.h>25#include <gmock/gmock.h>
2626
27namespace mi = mir::input;27namespace mi = mir::input;
28namespace mia = mir::input::android;28namespace miat = mir::input::android::transport;
2929
30TEST(AndroidInputLexicon, translates_key_events)30TEST(AndroidInputLexicon, translates_key_events)
31{31{
@@ -48,7 +48,7 @@
48 down_time, event_time);48 down_time, event_time);
4949
50 MirEvent mir_ev;50 MirEvent mir_ev;
51 mia::Lexicon::translate(android_key_ev, mir_ev);51 miat::Lexicon::translate(android_key_ev, mir_ev);
5252
53 // Common event properties53 // Common event properties
54 EXPECT_EQ(device_id, mir_ev.device_id);54 EXPECT_EQ(device_id, mir_ev.device_id);
@@ -121,7 +121,7 @@
121 event_time, pointer_count, &pointer_properties, &pointer_coords);121 event_time, pointer_count, &pointer_properties, &pointer_coords);
122122
123 MirEvent mir_ev;123 MirEvent mir_ev;
124 mia::Lexicon::translate(android_motion_ev, mir_ev);124 miat::Lexicon::translate(android_motion_ev, mir_ev);
125125
126 // Common event properties126 // Common event properties
127 EXPECT_EQ(device_id, mir_ev.device_id);127 EXPECT_EQ(device_id, mir_ev.device_id);
128128
=== modified file 'tests/unit-tests/input/android/test_android_input_window_handle.cpp'
--- tests/unit-tests/input/android/test_android_input_window_handle.cpp 2013-03-29 16:51:35 +0000
+++ tests/unit-tests/input/android/test_android_input_window_handle.cpp 2013-04-03 18:49:21 +0000
@@ -80,7 +80,7 @@
8080
81 auto info = handle.getInfo();81 auto info = handle.getInfo();
8282
83 EXPECT_EQ(testing_surface_name, info->name);83 EXPECT_EQ(droidinput::String8(testing_surface_name.c_str()), info->name);
8484
85 EXPECT_EQ(testing_server_fd, info->inputChannel->getFd());85 EXPECT_EQ(testing_server_fd, info->inputChannel->getFd());
8686

Subscribers

People subscribed via source and target branches