Mir

Merge lp:~andreas-pokorny/mir/fix-1531517 into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Alexandros Frantzis
Approved revision: no longer in the source branch.
Merged at revision: 3243
Proposed branch: lp:~andreas-pokorny/mir/fix-1531517
Merge into: lp:mir
Diff against target: 362 lines (+241/-44)
2 files modified
src/server/input/android/input_sender.cpp (+69/-28)
tests/unit-tests/input/android/test_android_input_sender.cpp (+172/-16)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/fix-1531517
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Mir CI Bot continuous-integration Approve
Brandon Schaefer (community) Approve
Kevin DuBois (community) Approve
Alexandros Frantzis (community) Approve
Review via email: mp+282439@code.launchpad.net

Commit message

Never encode more than one action per event

Android InputTransport has only one action parameter per event. Within that the contact that caused the action is also encoded. So until we replace or extend the input transport protocol, we have to split up MirEvents, to not lose touch up/down changes.

Description of the change

This change splits a MirEvent into several input transport messages when more than one contact was changed.

Alternatively to this approach we could 'just' change the InputTransport protocol... But I would wait with that when bschaefer gets around to add the cookie.. Additionally Daniel D'Andrada indicated that qt might not like seeing multiple state changes, at least there was some uncertainty.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

I find it hard to follow the logic in the main loop, although this could just be a result of my unfamiliarity with the domain. Perhaps breaking up the code into multiple distinct passes over the touch points, each pass performing a simple task and setting up state for the next pass, would make the code clearer.

I don't see anything wrong with the code, but I am not confident enough to "approve" either, so "abstain" :)

review: Abstain
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3241
https://mir-jenkins.ubuntu.com/job/mir-ci/37/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/37/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/37/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> I find it hard to follow the logic in the main loop, although this could just
> be a result of my unfamiliarity with the domain. Perhaps breaking up the code
> into multiple distinct passes over the touch points, each pass performing a
> simple task and setting up state for the next pass, would make the code
> clearer.
>
> I don't see anything wrong with the code, but I am not confident enough to
> "approve" either, so "abstain" :)

fair enough.
Hm I cannot see a simple solution .. I have three types up:
* up contacts have to be sent as change events until they have been processed then they have to be ignored.
* change contact are added always
* down contacts have to be omitted until they get processed.. then they have to be sent as change contacts..

ah.. yeah i guess that could turn into simpler code. Will give it a try.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3242
https://mir-jenkins.ubuntu.com/job/mir-ci/38/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/38/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/38/rebuild

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

PASSED: Continuous integration, rev:3242
http://jenkins.qa.ubuntu.com/job/mir-ci/6002/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5515
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4422
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5471
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/267
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/326
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/326/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/326
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/326/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5468
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5468/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7942
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26607
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/263
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/263/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/121
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26611

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6002/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3243
https://mir-jenkins.ubuntu.com/job/mir-ci/50/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/50/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/50/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

OK. I am still missing some domain knowledge about why things are done this way, but the code is clearer. Thanks.

review: Approve
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3244
https://mir-jenkins.ubuntu.com/job/mir-ci/51/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/51/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/51/rebuild

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

PASSED: Continuous integration, rev:3243
http://jenkins.qa.ubuntu.com/job/mir-ci/6015/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5531
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4438
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5487
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/276
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/339
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/339/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/339
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/339/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5484
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5484/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7955
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26643
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/272
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/272/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/130
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26646

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6015/rebuild

review: Approve (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

LGTM. For my changes ill just be hard coding an uint8_t[20] for the mac, sooo this wont cause me any issues. Which will just give me a operator= copy/move for the mac anyway soo no fancy changes needed on my end here.

Sooo really depends on whos branch lands first :), should be a simple conflict (if any)

One things:
+#include <unordered_set>
+ std::unordered_set<size_t> sent_indices;

Doesnt seem to be used?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:3244
http://jenkins.qa.ubuntu.com/job/mir-ci/6016/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5532
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4439
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5488
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/277
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/340
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/340/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/340
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/340/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5485
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5485/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7956
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26653
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/273
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/273/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/131
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26666

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6016/rebuild

review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

lgtm

review: Approve
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> LGTM. For my changes ill just be hard coding an uint8_t[20] for the mac, sooo
> this wont cause me any issues. Which will just give me a operator= copy/move
> for the mac anyway soo no fancy changes needed on my end here.
>
> Sooo really depends on whos branch lands first :), should be a simple conflict
> (if any)
>
> One things:
> +#include <unordered_set>
> + std::unordered_set<size_t> sent_indices;
>
> Doesnt seem to be used?

yes removed that

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

LGTM

review: Approve
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3245
https://mir-jenkins.ubuntu.com/job/mir-ci/62/
Executed test runs:
    None: https://mir-jenkins.ubuntu.com/job/generic-update-mp/62/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/62/rebuild

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

PASSED: Continuous integration, rev:3245
http://jenkins.qa.ubuntu.com/job/mir-ci/6026/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5542
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4449
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5498
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/282
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/350
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/350/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/350
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/350/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5495
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5495/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/7965
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26692
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/278
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/278/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/136
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/26693

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6026/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/input/android/input_sender.cpp'
2--- src/server/input/android/input_sender.cpp 2016-01-08 09:20:07 +0000
3+++ src/server/input/android/input_sender.cpp 2016-01-14 23:05:33 +0000
4@@ -254,40 +254,81 @@
5
6 droidinput::status_t mia::InputSender::ActiveTransfer::send_touch_event(uint32_t seq, MirEvent const& event)
7 {
8+ droidinput::status_t ret = droidinput::OK;
9 droidinput::PointerCoords coords[MIR_INPUT_EVENT_MAX_POINTER_COUNT];
10 droidinput::PointerProperties properties[MIR_INPUT_EVENT_MAX_POINTER_COUNT];
11- std::memset(&coords, 0, sizeof(coords));
12- std::memset(&properties, 0, sizeof(properties));
13-
14 auto input_event = mir_event_get_input_event(&event);
15 auto touch = mir_input_event_get_touch_event(input_event);
16+ std::chrono::nanoseconds const event_time{mir_input_event_get_event_time(input_event)};
17+ auto const x_offset = 0.0f;
18+ auto const y_offset = 0.0f;
19+ auto const x_precision = 0;
20+ auto const y_precision = 0;
21+ auto const flags = 0;
22+ auto const edge_flags = 0;
23+ auto const button_state = 0;
24+
25+ struct StateChange
26+ {
27+ int android_action;
28+ size_t index;
29+ };
30+
31+ std::vector<StateChange> state_changes;
32 for (size_t i = 0, e = mir_touch_event_point_count(touch); i != e; ++i)
33 {
34- // Note: this assumes that: x == raw_x + x_offset;
35- // here x, y is used instead of the raw co-ordinates and offset is set to zero
36- coords[i].setAxisValue(AMOTION_EVENT_AXIS_X, mir_touch_event_axis_value(touch, i, mir_touch_axis_x));
37- coords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, mir_touch_event_axis_value(touch, i, mir_touch_axis_y));
38- coords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, mir_touch_event_axis_value(touch, i, mir_touch_axis_touch_major));
39- coords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, mir_touch_event_axis_value(touch, i, mir_touch_axis_touch_minor));
40- coords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, mir_touch_event_axis_value(touch, i, mir_touch_axis_size));
41- coords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mir_touch_event_axis_value(touch, i, mir_touch_axis_pressure));
42- properties[i].toolType = mia::android_tool_type_from_mir(mir_touch_event_tooltype(touch, i));
43- properties[i].id = mir_touch_event_id(touch, i);
44- }
45-
46- std::chrono::nanoseconds const event_time{mir_input_event_get_event_time(input_event)};
47- auto const x_offset = 0.0f;
48- auto const y_offset = 0.0f;
49- auto const x_precision = 0;
50- auto const y_precision = 0;
51- auto const flags = 0;
52- auto const edge_flags = 0;
53- auto const button_state = 0;
54- return publisher.publishMotionEvent(seq, mir_input_event_get_device_id(input_event), AINPUT_SOURCE_TOUCHSCREEN,
55- mia::extract_android_action_from(event), flags, edge_flags,
56- mia::android_modifiers_from_mir(mir_touch_event_modifiers(touch)), button_state,
57- x_offset, y_offset, x_precision, y_precision, event.motion.mac, event_time,
58- event_time, mir_touch_event_point_count(touch), properties, coords);
59+ auto const action = mir_touch_event_action(touch, i);
60+ if (action == mir_touch_action_down)
61+ state_changes.push_back(StateChange{AMOTION_EVENT_ACTION_DOWN, i});
62+ if (action == mir_touch_action_up)
63+ state_changes.push_back(StateChange{AMOTION_EVENT_ACTION_UP, i});
64+ }
65+
66+ if (state_changes.empty())
67+ state_changes.push_back(StateChange{AMOTION_EVENT_ACTION_MOVE, 0});
68+
69+ for (auto state_change : state_changes)
70+ {
71+ std::memset(&coords, 0, sizeof(coords));
72+ std::memset(&properties, 0, sizeof(properties));
73+
74+ int contacts_in_event = 0;
75+ int action_index = 0;
76+ for (size_t i = 0, e = mir_touch_event_point_count(touch); i != e; ++i)
77+ {
78+ auto const action = mir_touch_event_action(touch, i);
79+
80+ if (i == state_change.index)
81+ action_index = contacts_in_event;
82+
83+ // before a touch up state change got processed it is treated as 'change', skipped otherwise
84+ // after a touch down state change got processed it is treated as 'change', skipped otherwise
85+ if (i == state_change.index
86+ || (i < state_change.index && action != mir_touch_action_up)
87+ || (i > state_change.index && action != mir_touch_action_down))
88+ {
89+ coords[contacts_in_event].setAxisValue(AMOTION_EVENT_AXIS_X, mir_touch_event_axis_value(touch, i, mir_touch_axis_x));
90+ coords[contacts_in_event].setAxisValue(AMOTION_EVENT_AXIS_Y, mir_touch_event_axis_value(touch, i, mir_touch_axis_y));
91+ coords[contacts_in_event].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, mir_touch_event_axis_value(touch, i, mir_touch_axis_touch_major));
92+ coords[contacts_in_event].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, mir_touch_event_axis_value(touch, i, mir_touch_axis_touch_minor));
93+ coords[contacts_in_event].setAxisValue(AMOTION_EVENT_AXIS_SIZE, mir_touch_event_axis_value(touch, i, mir_touch_axis_size));
94+ coords[contacts_in_event].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mir_touch_event_axis_value(touch, i, mir_touch_axis_pressure));
95+ properties[contacts_in_event].toolType = mia::android_tool_type_from_mir(mir_touch_event_tooltype(touch, i));
96+ properties[contacts_in_event].id = mir_touch_event_id(touch, i);
97+ ++contacts_in_event;
98+ }
99+ }
100+
101+ state_change.android_action |= (action_index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
102+
103+ ret = publisher.publishMotionEvent(seq, mir_input_event_get_device_id(input_event), AINPUT_SOURCE_TOUCHSCREEN,
104+ state_change.android_action, flags, edge_flags,
105+ mia::android_modifiers_from_mir(mir_touch_event_modifiers(touch)),
106+ button_state, x_offset, y_offset, x_precision, y_precision, event.motion.mac,
107+ event_time, event_time, contacts_in_event, properties, coords);
108+ }
109+
110+ return ret;
111 }
112
113 droidinput::status_t mia::InputSender::ActiveTransfer::send_pointer_event(uint32_t seq, MirEvent const& event)
114
115=== modified file 'tests/unit-tests/input/android/test_android_input_sender.cpp'
116--- tests/unit-tests/input/android/test_android_input_sender.cpp 2016-01-08 09:20:07 +0000
117+++ tests/unit-tests/input/android/test_android_input_sender.cpp 2016-01-14 23:05:33 +0000
118@@ -17,10 +17,10 @@
119 */
120
121 #include "mir/events/event_private.h"
122-#include "mir/events/event_builders.h"
123
124 #include "src/server/input/android/android_input_channel.h"
125 #include "src/server/input/android/input_sender.h"
126+#include "src/server/input/default_event_builder.h"
127 #include "src/server/report/null_report_factory.h"
128
129 #include "mir/test/doubles/stub_scene_surface.h"
130@@ -35,6 +35,7 @@
131 #include "androidfw/InputTransport.h"
132
133 #include "mir/input/input_report.h"
134+#include "mir/cookie_factory.h"
135
136 #include <gtest/gtest.h>
137 #include <gmock/gmock.h>
138@@ -47,7 +48,6 @@
139 namespace mi = mir::input;
140 namespace ms = mir::scene;
141 namespace mia = mi::android;
142-namespace mev = mir::events;
143 namespace mt = mir::test;
144 namespace mr = mir::report;
145 namespace mtd = mt::doubles;
146@@ -90,6 +90,14 @@
147 std::shared_ptr<ms::Observer> observer;
148 };
149
150+class StubCookieFactory : public mir::cookie::CookieFactory
151+{
152+public:
153+ MirCookie timestamp_to_cookie(uint64_t const&) override { return {0, 0};}
154+ bool attest_timestamp(MirCookie const&) override {return true;}
155+ StubCookieFactory() = default;
156+};
157+
158 }
159
160 class AndroidInputSender : public ::testing::Test
161@@ -99,26 +107,29 @@
162 size_t const test_pointer_count = 2;
163 float const test_x_coord[2] = {12, 23};
164 float const test_y_coord[2] = {17, 9};
165- mir::geometry::Point const pos{100, 100};
166+ MirTouchTooltype const tool = mir_touch_tooltype_finger;
167+ float const pressure = 0.6f;
168+ float const major = 8;
169+ float const minor = 4;
170+ float const size = 8;
171 mir::geometry::Displacement const movement{10, -10};
172+ StubCookieFactory cookie_factory;
173+ mi::DefaultEventBuilder builder{MirInputDeviceId(), mt::fake_shared(cookie_factory)};
174
175 AndroidInputSender()
176- : key_event(mev::make_event(MirInputDeviceId(), std::chrono::nanoseconds(1), 0, mir_keyboard_action_down, 7,
177- test_scan_code, mir_input_event_modifier_none)),
178- motion_event(
179- mev::make_event(MirInputDeviceId(), std::chrono::nanoseconds(-1), 0, mir_input_event_modifier_none)),
180- pointer_event(mev::make_event(MirInputDeviceId(), std::chrono::nanoseconds(123), 0,
181- mir_input_event_modifier_none, mir_pointer_action_motion,
182- mir_pointer_button_primary, pos.x.as_float(), pos.y.as_float(), 0.0f, 0.0f,
183+ : key_event(builder.key_event(std::chrono::nanoseconds(1), mir_keyboard_action_down, 7, test_scan_code)),
184+ motion_event(builder.touch_event(std::chrono::nanoseconds(-1))),
185+ pointer_event(builder.pointer_event(std::chrono::nanoseconds(123), mir_pointer_action_motion,
186+ mir_pointer_button_primary, 0.0f, 0.0f,
187 movement.dx.as_float(), movement.dy.as_float()))
188
189 {
190 using namespace ::testing;
191
192- mev::add_touch(*motion_event, 0, mir_touch_action_change, mir_touch_tooltype_finger, test_x_coord[0], test_y_coord[0],
193- 24, 25, 26, 27);
194- mev::add_touch(*motion_event, 1, mir_touch_action_change, mir_touch_tooltype_finger, test_x_coord[1], test_y_coord[1],
195- 24, 25, 26, 27);
196+ builder.add_touch(*motion_event, 0, mir_touch_action_change, tool, test_x_coord[0], test_y_coord[0],
197+ pressure, major, minor, size);
198+ builder.add_touch(*motion_event, 1, mir_touch_action_change, tool, test_x_coord[1], test_y_coord[1],
199+ pressure, major, minor, size);
200
201 ON_CALL(event_factory, createKeyEvent()).WillByDefault(Return(&client_key_event));
202 ON_CALL(event_factory, createMotionEvent()).WillByDefault(Return(&client_motion_event));
203@@ -293,8 +304,6 @@
204
205 EXPECT_EQ(1, client_motion_event.getPointerCount());
206
207- EXPECT_EQ(pos.x.as_float(), client_motion_event.getX(0));
208- EXPECT_EQ(pos.y.as_float(), client_motion_event.getY(0));
209 EXPECT_EQ(movement.dx.as_float(), client_motion_event.getAxisValue(AMOTION_EVENT_AXIS_RX, 0));
210 EXPECT_EQ(movement.dy.as_float(), client_motion_event.getAxisValue(AMOTION_EVENT_AXIS_RY, 0));
211 EXPECT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, client_motion_event.getToolType(0));
212@@ -339,3 +348,150 @@
213 consumer.sendFinishedSignal(seq, false);
214 loop.trigger_pending_fds();
215 }
216+
217+TEST_F(AndroidInputSender, encodes_multiple_touch_contact_downs_as_multiple_events)
218+{
219+ // TODO When the rework of the transport encoding is finished we might want to revisit this decision
220+ register_surface();
221+
222+ auto touch_ev_with_simultaneous_down = builder.touch_event(std::chrono::nanoseconds(86));
223+ builder.add_touch(*touch_ev_with_simultaneous_down, 2, mir_touch_action_down, tool, 50, 60, pressure, major, minor, size);
224+ builder.add_touch(*touch_ev_with_simultaneous_down, 4, mir_touch_action_down, tool, 80, 90, pressure, major, minor, size);
225+
226+ sender.send_event(*touch_ev_with_simultaneous_down, channel);
227+
228+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
229+ EXPECT_EQ(&client_motion_event, event);
230+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, client_motion_event.getActionMasked());
231+ EXPECT_EQ(0, client_motion_event.getActionIndex());
232+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
233+ EXPECT_EQ(1, client_motion_event.getPointerCount());
234+
235+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
236+ EXPECT_EQ(&client_motion_event, event);
237+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, client_motion_event.getActionMasked());
238+ EXPECT_EQ(1, client_motion_event.getActionIndex());
239+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
240+ EXPECT_EQ(4, client_motion_event.getPointerId(1));
241+ EXPECT_EQ(2, client_motion_event.getPointerCount());
242+}
243+
244+TEST_F(AndroidInputSender, encodes_multiple_touch_contact_downs_as_multiple_events_but_keeps_only_moved_contacts_in_place)
245+{
246+ // TODO When the rework of the transport encoding is finished we might want to revisit this decision
247+ register_surface();
248+
249+ auto touch_ev_with_simultaneous_down = builder.touch_event(std::chrono::nanoseconds(86));
250+ builder.add_touch(*touch_ev_with_simultaneous_down, 2, mir_touch_action_down, tool, 50, 60, pressure, major, minor, size);
251+ builder.add_touch(*touch_ev_with_simultaneous_down, 3, mir_touch_action_change, tool, 10, 10, pressure, major, minor, size);
252+ builder.add_touch(*touch_ev_with_simultaneous_down, 4, mir_touch_action_down, tool, 80, 90, pressure, major, minor, size);
253+
254+ sender.send_event(*touch_ev_with_simultaneous_down, channel);
255+
256+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
257+ EXPECT_EQ(&client_motion_event, event);
258+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, client_motion_event.getActionMasked());
259+ EXPECT_EQ(0, client_motion_event.getActionIndex());
260+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
261+ EXPECT_EQ(3, client_motion_event.getPointerId(1));
262+ EXPECT_EQ(2, client_motion_event.getPointerCount());
263+
264+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
265+ EXPECT_EQ(&client_motion_event, event);
266+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, client_motion_event.getActionMasked());
267+ EXPECT_EQ(2, client_motion_event.getActionIndex());
268+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
269+ EXPECT_EQ(3, client_motion_event.getPointerId(1));
270+ EXPECT_EQ(4, client_motion_event.getPointerId(2));
271+ EXPECT_EQ(3, client_motion_event.getPointerCount());
272+}
273+
274+TEST_F(AndroidInputSender, encodes_multiple_releases_in_several_events)
275+{
276+ // TODO When the rework of the transport encoding is finished we might want to revisit this decision
277+ register_surface();
278+
279+ auto touch_ev_with_simultaneous_down = builder.touch_event(std::chrono::nanoseconds(86));
280+ builder.add_touch(*touch_ev_with_simultaneous_down, 2, mir_touch_action_up, tool, 50, 60, pressure, major, minor, size);
281+ builder.add_touch(*touch_ev_with_simultaneous_down, 3, mir_touch_action_change, tool, 10, 10, pressure, major, minor, size);
282+ builder.add_touch(*touch_ev_with_simultaneous_down, 4, mir_touch_action_up, tool, 80, 90, pressure, major, minor, size);
283+
284+ sender.send_event(*touch_ev_with_simultaneous_down, channel);
285+
286+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
287+ EXPECT_EQ(&client_motion_event, event);
288+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, client_motion_event.getActionMasked());
289+ EXPECT_EQ(0, client_motion_event.getActionIndex());
290+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
291+ EXPECT_EQ(3, client_motion_event.getPointerId(1));
292+ EXPECT_EQ(4, client_motion_event.getPointerId(2));
293+ EXPECT_EQ(3, client_motion_event.getPointerCount());
294+
295+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
296+ EXPECT_EQ(&client_motion_event, event);
297+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, client_motion_event.getActionMasked());
298+ EXPECT_EQ(1, client_motion_event.getActionIndex());
299+ EXPECT_EQ(3, client_motion_event.getPointerId(0));
300+ EXPECT_EQ(4, client_motion_event.getPointerId(1));
301+ EXPECT_EQ(2, client_motion_event.getPointerCount());
302+}
303+
304+TEST_F(AndroidInputSender, encodes_combinations_of_up_and_down_one_by_one)
305+{
306+ // TODO When the rework of the transport encoding is finished we might want to revisit this decision
307+ register_surface();
308+
309+ auto touch_ev_with_simultaneous_down = builder.touch_event(std::chrono::nanoseconds(86));
310+ builder.add_touch(*touch_ev_with_simultaneous_down, 2, mir_touch_action_up, tool, 50, 60, pressure, major, minor, size);
311+ builder.add_touch(*touch_ev_with_simultaneous_down, 3, mir_touch_action_change, tool, 10, 10, pressure, major, minor, size);
312+ builder.add_touch(*touch_ev_with_simultaneous_down, 4, mir_touch_action_down, tool, 80, 90, pressure, major, minor, size);
313+
314+ sender.send_event(*touch_ev_with_simultaneous_down, channel);
315+
316+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
317+ EXPECT_EQ(&client_motion_event, event);
318+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, client_motion_event.getActionMasked());
319+ EXPECT_EQ(0, client_motion_event.getActionIndex());
320+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
321+ EXPECT_EQ(3, client_motion_event.getPointerId(1));
322+ EXPECT_EQ(2, client_motion_event.getPointerCount());
323+
324+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
325+ EXPECT_EQ(&client_motion_event, event);
326+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, client_motion_event.getActionMasked());
327+ EXPECT_EQ(1, client_motion_event.getActionIndex());
328+ EXPECT_EQ(3, client_motion_event.getPointerId(0));
329+ EXPECT_EQ(4, client_motion_event.getPointerId(1));
330+ EXPECT_EQ(2, client_motion_event.getPointerCount());
331+}
332+
333+TEST_F(AndroidInputSender, encodes_combinations_of_down_and_up_one_by_one)
334+{
335+ // TODO When the rework of the transport encoding is finished we might want to revisit this decision
336+ register_surface();
337+
338+ auto touch_ev_with_simultaneous_down = builder.touch_event(std::chrono::nanoseconds(86));
339+ builder.add_touch(*touch_ev_with_simultaneous_down, 2, mir_touch_action_down, tool, 50, 60, pressure, major, minor, size);
340+ builder.add_touch(*touch_ev_with_simultaneous_down, 3, mir_touch_action_change, tool, 10, 10, pressure, major, minor, size);
341+ builder.add_touch(*touch_ev_with_simultaneous_down, 4, mir_touch_action_up, tool, 80, 90, pressure, major, minor, size);
342+
343+ sender.send_event(*touch_ev_with_simultaneous_down, channel);
344+
345+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
346+ EXPECT_EQ(&client_motion_event, event);
347+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, client_motion_event.getActionMasked());
348+ EXPECT_EQ(0, client_motion_event.getActionIndex());
349+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
350+ EXPECT_EQ(3, client_motion_event.getPointerId(1));
351+ EXPECT_EQ(4, client_motion_event.getPointerId(2));
352+ EXPECT_EQ(3, client_motion_event.getPointerCount());
353+
354+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
355+ EXPECT_EQ(&client_motion_event, event);
356+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, client_motion_event.getActionMasked());
357+ EXPECT_EQ(2, client_motion_event.getActionIndex());
358+ EXPECT_EQ(2, client_motion_event.getPointerId(0));
359+ EXPECT_EQ(3, client_motion_event.getPointerId(1));
360+ EXPECT_EQ(4, client_motion_event.getPointerId(2));
361+ EXPECT_EQ(3, client_motion_event.getPointerCount());
362+}

Subscribers

People subscribed via source and target branches