Merge lp:~dandrader/grail/lp1026962 into lp:grail

Proposed by Daniel d'Andrada
Status: Merged
Merged at revision: 232
Proposed branch: lp:~dandrader/grail/lp1026962
Merge into: lp:grail
Diff against target: 738 lines (+367/-253)
6 files modified
src/gesture.cpp (+13/-20)
test/regular/Makefile.am (+1/-0)
test/regular/grail-fixture.cpp (+222/-0)
test/regular/grail-fixture.h (+46/-0)
test/regular/intermittent_3touch.cpp (+7/-233)
test/regular/pending-end.cpp (+78/-0)
To merge this branch: bzr merge lp:~dandrader/grail/lp1026962
Reviewer Review Type Date Requested Status
Chase Douglas (community) Approve
Review via email: mp+116290@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Chase Douglas (chasedouglas) wrote :

Looks good to me :).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/gesture.cpp'
2--- src/gesture.cpp 2012-05-09 17:18:29 +0000
3+++ src/gesture.cpp 2012-07-23 14:05:24 +0000
4@@ -104,31 +104,24 @@
5 * Update a gesture with the passed in frame event and list of modified touches
6 */
7 void Gesture::Update(UFEvent frame_event, TouchSet& modified_touches) {
8- if (IsPhysicallyEnded()) {
9- /* The new event may have given us ownership of all the touches, in which
10- * case we need to send all gesture slices to the client */
11- if (IsActive())
12- FlushSlices();
13-
14- /* If the gesture ended, no need to update state */
15- return;
16- }
17-
18- UFFrame frame;
19- UFStatus status = frame_event_get_property(frame_event, UFEventPropertyFrame,
20- &frame);
21- if (status != UFStatusSuccess) {
22- LOG(Warn) << "failed to get frame from event\n";
23+
24+ if (ended_) {
25+ /* Now the only thing that can happen is receiving ownership */
26+ if (!owned_ && !not_owned_) {
27+ CheckOwned();
28+ if (IsActive())
29+ FlushSlices();
30+ }
31 return;
32 }
33
34 TouchSet ended_touches;
35 bool touch_found = false;
36 for (UFTouchId touch_id : modified_touches) {
37- const auto& it = current_touches_.find(touch_id);
38+ const auto& it = all_touches_.find(touch_id);
39
40 /* If the touch is not part of this gesture, skip it */
41- if (it != current_touches_.end())
42+ if (it != all_touches_.end())
43 touch_found = true;
44 else
45 continue;
46@@ -158,15 +151,15 @@
47 slice = new UGSlice(*this, frame_event, current_touches_,
48 recognized_);
49 last_slice_ = SharedUGSlice(slice);
50- } else {
51+ slices_.push(last_slice_);
52+ } else if (!IsPhysicallyEnded()) {
53 UGSlice* slice;
54 /* Create gesture update or end slice */
55 slice = new UGSlice(last_slice_, *this, frame_event, current_touches_);
56 last_slice_ = SharedUGSlice(slice);
57+ slices_.push(last_slice_);
58 }
59
60- slices_.push(last_slice_);
61-
62 for (UFTouchId touch_id : ended_touches)
63 current_touches_.erase(touch_id);
64
65
66=== modified file 'test/regular/Makefile.am'
67--- test/regular/Makefile.am 2012-07-11 13:22:47 +0000
68+++ test/regular/Makefile.am 2012-07-23 14:05:24 +0000
69@@ -27,6 +27,7 @@
70 grail-fixture.h \
71 intermittent_3touch.cpp \
72 one-touch-gest-finished.cpp \
73+ pending-end.cpp \
74 still-gest-finishes.cpp \
75 subscription.cpp
76
77
78=== modified file 'test/regular/grail-fixture.cpp'
79--- test/regular/grail-fixture.cpp 2012-07-11 13:22:17 +0000
80+++ test/regular/grail-fixture.cpp 2012-07-23 14:05:24 +0000
81@@ -56,6 +56,7 @@
82 device_ptr->direct = 1;
83 device_ptr->axes.push_back(axis_x_struct);
84 device_ptr->axes.push_back(axis_y_struct);
85+ /* pixels/m */
86 device_ptr->window_resolution_x = 3764.70;
87 device_ptr->window_resolution_y = 3764.70;
88 }
89@@ -144,6 +145,227 @@
90 return subscription;
91 }
92
93+void GrailTest::BeginTouch(int touch_id)
94+{
95+ BeginTouchWindowCoords(touch_id, touch_id * 10.0f, 0.0f);
96+}
97+
98+void GrailTest::BeginTouchWindowCoords(int touch_id, float window_x, float window_y)
99+{
100+ struct UFTouch_ touch_struct;
101+ touch_struct.id = touch_id;
102+ touch_struct.state = UFTouchStateBegin;
103+ touch_struct.time = time;
104+ touch_struct.start_time = touch_struct.time;
105+ touch_struct.window_x = window_x;
106+ touch_struct.window_y = window_y;
107+ touch_struct.owned = 0;
108+ touch_struct.pending_end = 0;
109+
110+ touches.push_back(touch_struct);
111+
112+ SendFrameEvent(time, fake_window_id, touches);
113+
114+ // leave it in a neutral state for next uses of touches vector
115+ touches[touches.size()-1].state = UFTouchStateUpdate;
116+}
117+
118+void GrailTest::GiveTouchOwnership(int touch_id)
119+{
120+ auto iterator = FindTouch(touch_id);
121+ iterator->state = UFTouchStateUpdate;
122+ iterator->owned = 1; // ownership will trigger delivery of grail events.
123+ iterator->time = time;
124+
125+ SendFrameEvent(time, fake_window_id, touches);
126+}
127+
128+void GrailTest::SetTouchWindowCoords(int touch_id, float window_x, float window_y)
129+{
130+ auto iterator = FindTouch(touch_id);
131+ iterator->window_x = window_x;
132+ iterator->window_y = window_y;
133+}
134+
135+void GrailTest::UpdateTouches()
136+{
137+ for (struct UFTouch_ &touch : touches)
138+ {
139+ touch.time = time;
140+ }
141+ SendFrameEvent(time, fake_window_id, touches);
142+}
143+
144+void GrailTest::EndTouch(int touch_id)
145+{
146+ auto iterator = FindTouch(touch_id);
147+ iterator->state = UFTouchStateEnd;
148+ iterator->time = time;
149+
150+ SendFrameEvent(time, fake_window_id, touches);
151+
152+ touches.erase(iterator);
153+}
154+
155+std::vector<struct UFTouch_>::iterator GrailTest::FindTouch(unsigned int touch_id)
156+{
157+ std::vector<struct UFTouch_>::iterator it = touches.begin();
158+
159+ while (it != touches.end())
160+ {
161+ if (it->id == touch_id)
162+ return it;
163+ ++it;
164+ }
165+
166+ return it;
167+}
168+
169+void GrailTest::ProcessGrailEvents()
170+{
171+ UGEvent grail_event;
172+ UGStatus get_event_status;
173+
174+ do
175+ {
176+ get_event_status = grail_get_event(grail_handle, &grail_event);
177+ if (get_event_status != UGStatusSuccess)
178+ continue;
179+
180+ switch (grail_event_get_type(grail_event))
181+ {
182+ case UGEventTypeSlice:
183+ {
184+ UGStatus status;
185+ UGSlice slice;
186+ status = grail_event_get_property(grail_event, UGEventPropertySlice, &slice);
187+ ASSERT_EQ(UGStatusSuccess, status);
188+ ProcessSlice(slice);
189+ }
190+ break;
191+ default:
192+ FAIL(); // we are only expecting slice events
193+ }
194+
195+ grail_event_unref(grail_event);
196+ }
197+ while (get_event_status == UGStatusSuccess);
198+
199+ ASSERT_EQ(UGStatusErrorNoEvent, get_event_status);
200+}
201+
202+void GrailTest::ProcessSlice(UGSlice slice)
203+{
204+ switch (grail_slice_get_state(slice))
205+ {
206+ case UGGestureStateBegin:
207+ AddNewGesture(slice);
208+ break;
209+ case UGGestureStateUpdate:
210+ UpdateGesture(slice);
211+ break;
212+ case UGGestureStateEnd:
213+ EndGesture(slice);
214+ break;
215+ default:
216+ FAIL();
217+ }
218+}
219+
220+GrailGesture *GrailTest::GestureWithId(unsigned int id)
221+{
222+ GrailGesture *gesture = nullptr;
223+
224+ for (GrailGesture &other_gesture : grail_gestures)
225+ {
226+ if (id == other_gesture.id)
227+ {
228+ gesture = &other_gesture;
229+ break;
230+ }
231+ }
232+
233+ return gesture;
234+}
235+
236+void GrailTest::AddNewGesture(UGSlice slice)
237+{
238+ unsigned int gesture_id;
239+ UGStatus status = grail_slice_get_property(slice, UGSlicePropertyId, &gesture_id);
240+ ASSERT_EQ(UGStatusSuccess, status);
241+
242+ // there should be no gesture with this id
243+ ASSERT_EQ(nullptr, GestureWithId(gesture_id));
244+
245+ GrailGesture gesture;
246+ gesture.id = gesture_id;
247+
248+ unsigned int num_touches;
249+ status = grail_slice_get_property(slice, UGSlicePropertyNumTouches, &num_touches);
250+ ASSERT_EQ(UGStatusSuccess, status);
251+ for (unsigned int i = 0; i < num_touches; ++i)
252+ {
253+ UFTouchId touch_id;
254+ status = grail_slice_get_touch_id(slice, i, &touch_id);
255+ ASSERT_EQ(UGStatusSuccess, status);
256+ gesture.touches.insert(touch_id);
257+ }
258+
259+ gesture.construction_finished = grail_slice_get_construction_finished(slice);
260+ gesture.state = UGGestureStateBegin;
261+
262+ grail_gestures.push_back(gesture);
263+}
264+
265+void GrailTest::UpdateGesture(UGSlice slice)
266+{
267+ GrailGesture *gesture = nullptr;
268+ unsigned int gesture_id;
269+
270+ UGStatus status = grail_slice_get_property(slice, UGSlicePropertyId, &gesture_id);
271+ ASSERT_EQ(UGStatusSuccess, status);
272+
273+ gesture = GestureWithId(gesture_id);
274+
275+ // the gesture must already exist
276+ ASSERT_NE(nullptr, gesture);
277+
278+ if (grail_slice_get_construction_finished(slice))
279+ {
280+ gesture->construction_finished = true;
281+ }
282+ else
283+ {
284+ // can't go back from true to false
285+ ASSERT_FALSE(gesture->construction_finished);
286+ }
287+
288+ ASSERT_TRUE(gesture->state == UGGestureStateBegin
289+ || gesture->state == UGGestureStateUpdate);
290+ gesture->state = UGGestureStateUpdate;
291+}
292+
293+void GrailTest::EndGesture(UGSlice slice)
294+{
295+ GrailGesture *gesture = nullptr;
296+ unsigned int gesture_id;
297+
298+ UGStatus status = grail_slice_get_property(slice, UGSlicePropertyId, &gesture_id);
299+ ASSERT_EQ(UGStatusSuccess, status);
300+
301+ gesture = GestureWithId(gesture_id);
302+
303+ // the gesture must already exist
304+ ASSERT_NE(nullptr, gesture);
305+
306+ gesture->construction_finished = grail_slice_get_construction_finished(slice);
307+ ASSERT_TRUE(gesture->construction_finished);
308+
309+ ASSERT_TRUE(gesture->state == UGGestureStateBegin
310+ || gesture->state == UGGestureStateUpdate);
311+ gesture->state = UGGestureStateEnd;
312+}
313+
314 void GrailTest::PrintPendingGestures()
315 {
316 UGEvent grail_event;
317
318=== modified file 'test/regular/grail-fixture.h'
319--- test/regular/grail-fixture.h 2012-07-11 13:22:17 +0000
320+++ test/regular/grail-fixture.h 2012-07-23 14:05:24 +0000
321@@ -5,6 +5,21 @@
322 #include <utouch/grail.h>
323 #include "frame_mock.h"
324
325+#include <list>
326+#include <set>
327+
328+class GrailGesture
329+{
330+ public:
331+ bool HasTouch(UFTouchId touch_id) const
332+ {
333+ return touches.find(touch_id) != touches.end();
334+ }
335+ unsigned int id;
336+ std::set<UFTouchId> touches;
337+ bool construction_finished;
338+ UGGestureState state;
339+};
340
341 class GrailTest : public ::testing::Test
342 {
343@@ -38,6 +53,21 @@
344 std::vector<struct UFTouch_> &touches);
345 void SendDeviceAddedEvent(uint64_t time);
346
347+ void BeginTouch(int touch_id);
348+ void BeginTouchWindowCoords(int touch_id, float window_x, float window_y);
349+ void GiveTouchOwnership(int touch_id);
350+ void SetTouchWindowCoords(int touch_id, float window_x, float window_y);
351+ /* Updates the time of all touches in the "touches" vector and sends that vector
352+ in a frame event to grail */
353+ void UpdateTouches();
354+ void EndTouch(int touch_id);
355+ std::vector<struct UFTouch_>::iterator FindTouch(unsigned int touch_id);
356+
357+ /* Fetches and processes all pending grail events, updating grail_gestures
358+ list accordingly. */
359+ void ProcessGrailEvents();
360+ GrailGesture *GestureWithId(unsigned int id);
361+
362 /* Helper function for debugging purposes.
363 Prints all gestures in grail's queue.
364 */
365@@ -46,6 +76,22 @@
366
367 UGHandle grail_handle;
368 std::shared_ptr<struct UFDevice_> device_ptr;
369+
370+ uint64_t time;
371+ UFWindowId fake_window_id;
372+ std::vector<struct UFTouch_> touches;
373+
374+ /*
375+ A representation of the currently active gestures according to the grail events
376+ fetched by ProcessGrailEvents()
377+ */
378+ std::list<GrailGesture> grail_gestures;
379+
380+ private:
381+ void ProcessSlice(UGSlice slice);
382+ void AddNewGesture(UGSlice slice);
383+ void UpdateGesture(UGSlice slice);
384+ void EndGesture(UGSlice slice);
385 };
386
387 #endif // GRAIL_FIXTURE
388
389=== modified file 'test/regular/intermittent_3touch.cpp'
390--- test/regular/intermittent_3touch.cpp 2012-07-11 13:22:47 +0000
391+++ test/regular/intermittent_3touch.cpp 2012-07-23 14:05:24 +0000
392@@ -1,234 +1,9 @@
393 #include "grail-fixture.h"
394
395-#include <list>
396-#include <set>
397-
398-class GrailGesture
399-{
400- public:
401- bool HasTouch(UFTouchId touch_id) const
402- {
403- return touches.find(touch_id) != touches.end();
404- }
405- unsigned int id;
406- std::set<UFTouchId> touches;
407- bool construction_finished;
408-};
409-
410 class Intermittent3TouchTest : public GrailTest
411 {
412- protected:
413-
414- void BeginTouch(int touch_id);
415- void GiveTouchOwnership(int touch_id);
416- void EndTouch(int touch_id);
417- std::vector<struct UFTouch_>::iterator FindTouch(unsigned int touch_id);
418- void ProcessGrailEvents();
419- void ProcessSlice(UGSlice slice);
420- void AddNewGesture(UGSlice slice);
421- void UpdateGesture(UGSlice slice);
422- void EndGesture(UGSlice slice);
423- GrailGesture *GestureWithId(unsigned int id);
424-
425- uint64_t time;
426- UFWindowId fake_window_id;
427-
428- std::vector<struct UFTouch_> touches;
429-
430- std::list<GrailGesture> grail_gestures;
431 };
432
433-void Intermittent3TouchTest::BeginTouch(int touch_id)
434-{
435- struct UFTouch_ touch_struct;
436- touch_struct.id = touch_id;
437- touch_struct.state = UFTouchStateBegin;
438- touch_struct.time = time;
439- touch_struct.start_time = touch_struct.time;
440- touch_struct.owned = 0;
441- touch_struct.pending_end = 0;
442-
443- touches.push_back(touch_struct);
444-
445- SendFrameEvent(time, fake_window_id, touches);
446-}
447-
448-void Intermittent3TouchTest::GiveTouchOwnership(int touch_id)
449-{
450- auto iterator = FindTouch(touch_id);
451- iterator->state = UFTouchStateUpdate;
452- iterator->owned = 1; // ownership will trigger delivery of grail events.
453- iterator->time = time;
454-
455- SendFrameEvent(time, fake_window_id, touches);
456-}
457-
458-void Intermittent3TouchTest::EndTouch(int touch_id)
459-{
460- auto iterator = FindTouch(touch_id);
461- iterator->state = UFTouchStateEnd;
462- iterator->time = time;
463-
464- SendFrameEvent(time, fake_window_id, touches);
465-
466- touches.erase(iterator);
467-}
468-
469-std::vector<struct UFTouch_>::iterator Intermittent3TouchTest::FindTouch(unsigned int touch_id)
470-{
471- std::vector<struct UFTouch_>::iterator it = touches.begin();
472-
473- while (it != touches.end())
474- {
475- if (it->id == touch_id)
476- return it;
477- ++it;
478- }
479-
480- return it;
481-}
482-
483-void Intermittent3TouchTest::ProcessGrailEvents()
484-{
485- UGEvent grail_event;
486- UGStatus get_event_status;
487-
488- do
489- {
490- get_event_status = grail_get_event(grail_handle, &grail_event);
491- if (get_event_status != UGStatusSuccess)
492- continue;
493-
494- switch (grail_event_get_type(grail_event))
495- {
496- case UGEventTypeSlice:
497- {
498- UGStatus status;
499- UGSlice slice;
500- status = grail_event_get_property(grail_event, UGEventPropertySlice, &slice);
501- ASSERT_EQ(UGStatusSuccess, status);
502- ProcessSlice(slice);
503- }
504- break;
505- default:
506- FAIL(); // we are only expecting slice events
507- }
508-
509- grail_event_unref(grail_event);
510- }
511- while (get_event_status == UGStatusSuccess);
512-
513- ASSERT_EQ(UGStatusErrorNoEvent, get_event_status);
514-}
515-
516-void Intermittent3TouchTest::ProcessSlice(UGSlice slice)
517-{
518- switch (grail_slice_get_state(slice))
519- {
520- case UGGestureStateBegin:
521- AddNewGesture(slice);
522- break;
523- case UGGestureStateUpdate:
524- UpdateGesture(slice);
525- break;
526- case UGGestureStateEnd:
527- EndGesture(slice);
528- break;
529- default:
530- FAIL();
531- }
532-}
533-
534-GrailGesture *Intermittent3TouchTest::GestureWithId(unsigned int id)
535-{
536- GrailGesture *gesture = nullptr;
537-
538- for (auto other_gesture : grail_gestures)
539- {
540- if (id == other_gesture.id)
541- {
542- gesture = &other_gesture;
543- break;
544- }
545- }
546-
547- return gesture;
548-}
549-
550-void Intermittent3TouchTest::AddNewGesture(UGSlice slice)
551-{
552- unsigned int gesture_id;
553- UGStatus status = grail_slice_get_property(slice, UGSlicePropertyId, &gesture_id);
554- ASSERT_EQ(UGStatusSuccess, status);
555-
556- // there should be no gesture with this id
557- ASSERT_EQ(nullptr, GestureWithId(gesture_id));
558-
559- GrailGesture gesture;
560- gesture.id = gesture_id;
561-
562- unsigned int num_touches;
563- status = grail_slice_get_property(slice, UGSlicePropertyNumTouches, &num_touches);
564- ASSERT_EQ(UGStatusSuccess, status);
565- for (unsigned int i = 0; i < num_touches; ++i)
566- {
567- UFTouchId touch_id;
568- status = grail_slice_get_touch_id(slice, i, &touch_id);
569- ASSERT_EQ(UGStatusSuccess, status);
570- gesture.touches.insert(touch_id);
571- }
572-
573- gesture.construction_finished = grail_slice_get_construction_finished(slice);
574-
575- grail_gestures.push_back(gesture);
576-}
577-
578-void Intermittent3TouchTest::UpdateGesture(UGSlice slice)
579-{
580- GrailGesture *gesture = nullptr;
581- unsigned int gesture_id;
582-
583- UGStatus status = grail_slice_get_property(slice, UGSlicePropertyId, &gesture_id);
584- ASSERT_EQ(UGStatusSuccess, status);
585-
586- gesture = GestureWithId(gesture_id);
587-
588- // the gesture must already exist
589- ASSERT_NE(nullptr, gesture);
590-
591- if (grail_slice_get_construction_finished(slice))
592- {
593- gesture->construction_finished = true;
594- }
595- else
596- {
597- // can't go back from true to false
598- ASSERT_FALSE(gesture->construction_finished);
599- }
600-}
601-
602-void Intermittent3TouchTest::EndGesture(UGSlice slice)
603-{
604- unsigned int gesture_id;
605- bool found = false;
606-
607- UGStatus status = grail_slice_get_property(slice, UGSlicePropertyId, &gesture_id);
608- ASSERT_EQ(UGStatusSuccess, status);
609-
610- for (auto it = grail_gestures.begin(); !found && it != grail_gestures.end(); ++it)
611- {
612- if (gesture_id == it->id)
613- {
614- found = true;
615- grail_gestures.erase(it);
616- break;
617- }
618- }
619-
620- // the gesture must already exist
621- ASSERT_TRUE(found);
622-}
623-
624 /*
625 Simulate the following situation:
626 The user lays 3 fingers over a touchscreen or trackpad
627@@ -276,7 +51,6 @@
628 */
629 ASSERT_EQ(1, grail_gestures.size());
630 ASSERT_EQ(3, grail_gestures.front().touches.size());
631- int first_gesture_id = grail_gestures.front().id;
632
633 time = 20531961;
634 EndTouch(18);
635@@ -296,13 +70,13 @@
636 gesture(id=1, touches={19,20,21}) begins
637 gesture(id=2, touches={19,20,21}) begins
638 */
639- ASSERT_EQ(nullptr, GestureWithId(first_gesture_id));
640- ASSERT_EQ(1, grail_gestures.size());
641- const GrailGesture &gesture = grail_gestures.front();
642- ASSERT_EQ(3, gesture.touches.size());
643- ASSERT_TRUE(gesture.HasTouch(19));
644- ASSERT_TRUE(gesture.HasTouch(20));
645- ASSERT_TRUE(gesture.HasTouch(21));
646+ ASSERT_EQ(UGGestureStateEnd, GestureWithId(0)->state);
647+ ASSERT_EQ(2, grail_gestures.size());
648+ GrailGesture *gesture = GestureWithId(1);
649+ ASSERT_EQ(3, gesture->touches.size());
650+ ASSERT_TRUE(gesture->HasTouch(19));
651+ ASSERT_TRUE(gesture->HasTouch(20));
652+ ASSERT_TRUE(gesture->HasTouch(21));
653
654 grail_subscription_delete(subscription);
655 }
656
657=== added file 'test/regular/pending-end.cpp'
658--- test/regular/pending-end.cpp 1970-01-01 00:00:00 +0000
659+++ test/regular/pending-end.cpp 2012-07-23 14:05:24 +0000
660@@ -0,0 +1,78 @@
661+#include "grail-fixture.h"
662+
663+/*
664+ Checks that once a touch whose end is pending gets finally owned its slices
665+ are sent to the client.
666+
667+ Regression test for https://bugs.launchpad.net/utouch-grail/+bug/1026962
668+ */
669+TEST_F(GrailTest, PendingEndImpedesGestures)
670+{
671+ UGStatus status;
672+ struct UFHandle_ frame_handle_struct;
673+ fake_window_id = 321;
674+
675+ status = grail_new(&frame_handle_struct, &grail_handle);
676+ ASSERT_EQ(UGStatusSuccess, status);
677+
678+ SendDeviceAddedEvent(time);
679+
680+ UGSubscription sub_3touch =
681+ CreateSubscription(3, UGGestureTypeTouch | UGGestureTypeDrag | UGGestureTypePinch,
682+ device_ptr.get(), fake_window_id);
683+ ASSERT_NE(nullptr, sub_3touch);
684+
685+ time = 13688369;
686+ BeginTouchWindowCoords(1 /* touch id */, 30.0f /* x */, 0.0f /* y */);
687+
688+ time = 13688369;
689+ BeginTouchWindowCoords(2, 40.0f, 0.0f);
690+ time = 13688372;
691+ GiveTouchOwnership(2);
692+
693+ time = 13688369;
694+ BeginTouchWindowCoords(3, 50.0f, 0.0f);
695+ time = 13688373;
696+ GiveTouchOwnership(3);
697+
698+ time = 13688430;
699+ grail_update_time(grail_handle, time);
700+
701+ /* Perform a 4 fingers drag. */
702+ for (int i=1; i<=4; ++i)
703+ {
704+ time += 100;
705+ SetTouchWindowCoords(1, 30.0f, i*10.0f);
706+ SetTouchWindowCoords(2, 40.0f, i*10.0f);
707+ SetTouchWindowCoords(3, 50.0f, i*10.0f);
708+ UpdateTouches();
709+ }
710+
711+ time = 13688877;
712+ FindTouch(1)->pending_end = 1;
713+ UpdateTouches();
714+
715+ ProcessGrailEvents();
716+ // no gesture slices yet since not all touches are owned
717+ ASSERT_EQ(0, grail_gestures.size());
718+
719+ time = 13688878;
720+ GiveTouchOwnership(1);
721+
722+ EndTouch(1);
723+
724+ ProcessGrailEvents();
725+ // Gesture slices should have been sent to the client by now
726+ ASSERT_EQ(1, grail_gestures.size());
727+ // Gesture must have ended since it cannot continue with only two touches.
728+ ASSERT_EQ(UGGestureStateEnd, grail_gestures.front().state);
729+
730+ EndTouch(2);
731+
732+ time = 13688880;
733+ EndTouch(3);
734+
735+ ProcessGrailEvents();
736+
737+ grail_subscription_delete(sub_3touch);
738+}

Subscribers

People subscribed via source and target branches