1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/view_manager/gesture_manager.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h"
9 #include "components/view_manager/gesture_manager_delegate.h"
10 #include "components/view_manager/public/cpp/keys.h"
11 #include "components/view_manager/server_view.h"
12 #include "components/view_manager/test_server_view_delegate.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/mojo/events/input_events.mojom.h"
16 namespace view_manager
{
19 const uint32_t kInvalidGestureId
= GestureManager::kInvalidGestureId
;
21 void MarkAsRespondsToTouch(ServerView
* view
) {
22 std::vector
<uint8_t> empty_vector
;
23 view
->SetProperty(mojo::kViewManagerKeyWantsTouchEvents
, &empty_vector
);
26 std::set
<uint32_t> SetWith(uint32_t v1
) {
27 std::set
<uint32_t> result
;
32 std::set
<uint32_t> SetWith(uint32_t v1
, uint32_t v2
) {
33 std::set
<uint32_t> result
;
39 std::set
<uint32_t> SetWith(uint32_t v1
, uint32_t v2
, uint32_t v3
) {
40 std::set
<uint32_t> result
;
47 std::string
EventTypeToString(mojo::EventType event_type
) {
49 case mojo::EVENT_TYPE_POINTER_CANCEL
:
51 case mojo::EVENT_TYPE_POINTER_DOWN
:
53 case mojo::EVENT_TYPE_POINTER_MOVE
:
55 case mojo::EVENT_TYPE_POINTER_UP
:
60 return std::string("unexpected event");
63 mojo::EventPtr
CreateEvent(mojo::EventType type
,
67 mojo::EventPtr
event(mojo::Event::New());
69 event
->pointer_data
= mojo::PointerData::New();
70 event
->pointer_data
->pointer_id
= pointer_id
;
71 event
->pointer_data
->x
= x
;
72 event
->pointer_data
->y
= y
;
76 struct CompareViewByConnectionId
{
77 bool operator()(const ServerView
* a
, const ServerView
* b
) {
78 return a
->id().connection_id
< b
->id().connection_id
;
82 std::string
IDsToString(const std::set
<uint32_t>& ids
) {
84 for (uint32_t id
: ids
) {
87 result
+= base::UintToString(id
);
92 std::string
GestureStateChangeToString(const ServerView
* view
,
93 const GestureStateChange
& change
) {
95 "connection=" + base::IntToString(view
->id().connection_id
);
96 if (change
.chosen_gesture
!= GestureManager::kInvalidGestureId
)
97 result
+= " chosen=" + base::UintToString(change
.chosen_gesture
);
98 if (!change
.canceled_gestures
.empty())
99 result
+= " canceled=" + IDsToString(change
.canceled_gestures
);
105 class TestGestureManagerDelegate
: public GestureManagerDelegate
{
107 TestGestureManagerDelegate() {}
108 ~TestGestureManagerDelegate() override
{}
110 std::string
GetAndClearDescriptions() {
111 const std::string
result(JoinString(descriptions_
, '\n'));
112 descriptions_
.clear();
116 std::vector
<std::string
>& descriptions() { return descriptions_
; }
118 void AppendDescriptionsFromResults(const ChangeMap
& change_map
) {
119 std::set
<const ServerView
*, CompareViewByConnectionId
> views_by_id
;
120 for (const auto& pair
: change_map
)
121 views_by_id
.insert(pair
.first
);
123 for (auto* view
: views_by_id
) {
124 descriptions_
.push_back(
125 GestureStateChangeToString(view
, change_map
.find(view
)->second
));
129 // GestureManagerDelegate:
130 void ProcessEvent(const ServerView
* view
,
131 mojo::EventPtr event
,
132 bool has_chosen_gesture
) override
{
133 descriptions_
.push_back(
134 EventTypeToString(event
->action
) + " pointer=" +
135 base::IntToString(event
->pointer_data
->pointer_id
) + " connection=" +
136 base::UintToString(view
->id().connection_id
) + " chosen=" +
137 (has_chosen_gesture
? "true" : "false"));
141 std::vector
<std::string
> descriptions_
;
143 DISALLOW_COPY_AND_ASSIGN(TestGestureManagerDelegate
);
146 class GestureManagerTest
: public testing::Test
{
149 : root_(&view_delegate_
, ViewId(1, 1)),
150 child_(&view_delegate_
, ViewId(2, 2)),
151 gesture_manager_(&gesture_delegate_
, &root_
) {
152 root_
.SetVisible(true);
153 MarkAsRespondsToTouch(&root_
);
154 root_
.SetBounds(gfx::Rect(0, 0, 100, 100));
156 ~GestureManagerTest() override
{}
158 void SetGestures(const ServerView
* view
,
160 uint32_t chosen_gesture_id
,
161 const std::set
<uint32_t>& possible_gesture_ids
,
162 const std::set
<uint32_t>& canceled_ids
) {
163 scoped_ptr
<ChangeMap
> result(
164 gesture_manager_
.SetGestures(view
, pointer_id
, chosen_gesture_id
,
165 possible_gesture_ids
, canceled_ids
));
166 gesture_delegate_
.AppendDescriptionsFromResults(*result
);
169 void AddChildView() {
170 MarkAsRespondsToTouch(&child_
);
171 child_
.SetVisible(true);
173 child_
.SetBounds(gfx::Rect(0, 0, 100, 100));
177 TestServerViewDelegate view_delegate_
;
180 TestGestureManagerDelegate gesture_delegate_
;
181 GestureManager gesture_manager_
;
184 DISALLOW_COPY_AND_ASSIGN(GestureManagerTest
);
187 TEST_F(GestureManagerTest
, SingleViewAndSingleGesture
) {
188 const int32_t pointer_id
= 1;
189 gesture_manager_
.ProcessEvent(
190 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
191 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
192 gesture_delegate_
.GetAndClearDescriptions());
194 // Choose this pointer.
195 SetGestures(&root_
, pointer_id
, 10u, SetWith(10u), std::set
<uint32_t>());
196 EXPECT_EQ("connection=1 chosen=10",
197 gesture_delegate_
.GetAndClearDescriptions());
200 TEST_F(GestureManagerTest
, SingleViewAndTwoGestures
) {
201 const int32_t pointer_id
= 1;
202 gesture_manager_
.ProcessEvent(
203 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
204 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
205 gesture_delegate_
.GetAndClearDescriptions());
207 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
208 std::set
<uint32_t>());
210 // Delegate should have got nothing.
211 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
213 // Cancel 10, 5 should become active.
214 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
217 EXPECT_EQ("connection=1 chosen=5 canceled=10",
218 gesture_delegate_
.GetAndClearDescriptions());
221 TEST_F(GestureManagerTest
, TwoViewsSingleGesture
) {
224 const int32_t pointer_id
= 1;
225 gesture_manager_
.ProcessEvent(
226 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
227 // Deepest child should be queried first.
228 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
229 gesture_delegate_
.GetAndClearDescriptions());
231 // Respond from the first view, which triggers the second to be queried.
232 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
233 std::set
<uint32_t>());
234 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
235 gesture_delegate_
.GetAndClearDescriptions());
237 // Respond with 5,10 for the second view. Should get nothing.
238 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
239 std::set
<uint32_t>());
240 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
242 // Cancel 10 in the child.
243 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
245 EXPECT_EQ("connection=2 canceled=10",
246 gesture_delegate_
.GetAndClearDescriptions());
248 // Choose 5 in the root. This should choose 5 in the root and cancel 5 in
250 SetGestures(&root_
, pointer_id
, 5u, SetWith(5u, 10u), SetWith(10u));
251 ASSERT_EQ(2u, gesture_delegate_
.descriptions().size());
252 EXPECT_EQ("connection=1 chosen=5 canceled=10",
253 gesture_delegate_
.descriptions()[0]);
254 EXPECT_EQ("connection=2 canceled=5", gesture_delegate_
.descriptions()[1]);
257 TEST_F(GestureManagerTest
, TwoViewsWaitForMoveToChoose
) {
260 const int32_t pointer_id
= 1;
261 gesture_manager_
.ProcessEvent(
262 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
263 // Deepest child should be queried first.
264 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
265 gesture_delegate_
.GetAndClearDescriptions());
267 // Send a move. The move should not be processed as GestureManager is
268 // still waiting for responses.
269 gesture_manager_
.ProcessEvent(
270 *CreateEvent(mojo::EVENT_TYPE_POINTER_MOVE
, pointer_id
, 6, 6));
271 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
273 // Respond from the first view, which triggers the second to be queried.
274 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
275 std::set
<uint32_t>());
276 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
277 gesture_delegate_
.GetAndClearDescriptions());
279 // Respond with 1,2 for the second view.
280 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(1u, 2u),
281 std::set
<uint32_t>());
282 // Now that we've responded to the down requests we should get a move for the
284 EXPECT_EQ("move pointer=1 connection=2 chosen=false",
285 gesture_delegate_
.GetAndClearDescriptions());
287 // Respond for the child, root should now get move.
288 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
289 std::set
<uint32_t>());
290 EXPECT_EQ("move pointer=1 connection=1 chosen=false",
291 gesture_delegate_
.GetAndClearDescriptions());
293 // Respond with nothing chosen for the root. Nothing should come in as no
295 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(1u, 2u),
296 std::set
<uint32_t>());
297 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
299 // Send another move event and respond with a chosen id.
300 gesture_manager_
.ProcessEvent(
301 *CreateEvent(mojo::EVENT_TYPE_POINTER_MOVE
, pointer_id
, 7, 7));
302 EXPECT_EQ("move pointer=1 connection=2 chosen=false",
303 gesture_delegate_
.GetAndClearDescriptions());
304 SetGestures(&child_
, pointer_id
, 5u, SetWith(5u, 10u), std::set
<uint32_t>());
305 ASSERT_EQ(3u, gesture_delegate_
.descriptions().size());
306 // Now that a gesture is chosen the move event is generated.
307 EXPECT_EQ("move pointer=1 connection=1 chosen=true",
308 gesture_delegate_
.descriptions()[0]);
309 EXPECT_EQ("connection=1 canceled=1,2", gesture_delegate_
.descriptions()[1]);
310 EXPECT_EQ("connection=2 chosen=5 canceled=10",
311 gesture_delegate_
.descriptions()[2]);
314 TEST_F(GestureManagerTest
, SingleViewNewPointerAfterChoose
) {
315 const int32_t pointer_id
= 1;
316 gesture_manager_
.ProcessEvent(
317 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
318 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
319 gesture_delegate_
.GetAndClearDescriptions());
322 SetGestures(&root_
, pointer_id
, 5u, SetWith(5u, 10u), std::set
<uint32_t>());
323 EXPECT_EQ("connection=1 chosen=5 canceled=10",
324 gesture_delegate_
.GetAndClearDescriptions());
326 // Start another down event with a different pointer.
327 const int32_t pointer_id2
= 2;
328 gesture_manager_
.ProcessEvent(
329 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id2
, 5, 5));
330 EXPECT_EQ("down pointer=2 connection=1 chosen=false",
331 gesture_delegate_
.GetAndClearDescriptions());
333 // For the new pointer supply the id of a gesture that has been chosen.
334 // Even though we didn't explicitly supply 5 as chosen, 5 is chosen because
335 // it's already in the chosen state for pointer 1.
336 SetGestures(&root_
, pointer_id2
, kInvalidGestureId
, SetWith(5u, 11u),
337 std::set
<uint32_t>());
338 EXPECT_EQ("connection=1 chosen=5 canceled=11",
339 gesture_delegate_
.GetAndClearDescriptions());
342 TEST_F(GestureManagerTest
, SingleViewChoosingConflictingGestures
) {
343 // For pointer1 choose 1 with 1,2,3 as possibilities.
344 const int32_t pointer1
= 1;
345 gesture_manager_
.ProcessEvent(
346 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer1
, 5, 5));
347 gesture_delegate_
.GetAndClearDescriptions();
348 SetGestures(&root_
, pointer1
, 1u, SetWith(1u, 2u, 3u), std::set
<uint32_t>());
349 EXPECT_EQ("connection=1 chosen=1 canceled=2,3",
350 gesture_delegate_
.GetAndClearDescriptions());
352 // For pointer2 choose 11 with 11,12 as possibilities.
353 const int32_t pointer2
= 2;
354 gesture_manager_
.ProcessEvent(
355 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer2
, 5, 5));
356 gesture_delegate_
.GetAndClearDescriptions();
357 SetGestures(&root_
, pointer2
, 11u, SetWith(11u, 12u), std::set
<uint32_t>());
358 EXPECT_EQ("connection=1 chosen=11 canceled=12",
359 gesture_delegate_
.GetAndClearDescriptions());
361 // For pointer3 choose 21 with 1,11,21 as possibilties.
362 const int32_t pointer3
= 3;
363 gesture_manager_
.ProcessEvent(
364 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer3
, 5, 5));
365 gesture_delegate_
.GetAndClearDescriptions();
366 SetGestures(&root_
, pointer3
, 21u, SetWith(1u, 11u, 21u),
367 std::set
<uint32_t>());
368 EXPECT_EQ("connection=1 chosen=21 canceled=1,11",
369 gesture_delegate_
.GetAndClearDescriptions());
372 TEST_F(GestureManagerTest
,
373 TwoViewsRespondingWithChosenGestureSendsRemainingEvents
) {
376 // Start two pointer downs, don't respond to either.
377 const int32_t pointer1
= 1;
378 gesture_manager_
.ProcessEvent(
379 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer1
, 5, 5));
380 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
381 gesture_delegate_
.GetAndClearDescriptions());
383 const int32_t pointer2
= 2;
384 gesture_manager_
.ProcessEvent(
385 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer2
, 5, 5));
386 EXPECT_EQ("down pointer=2 connection=2 chosen=false",
387 gesture_delegate_
.GetAndClearDescriptions());
389 // Queue up a move event for pointer1. The event should not be forwarded
390 // as we're still waiting.
391 gesture_manager_
.ProcessEvent(
392 *CreateEvent(mojo::EVENT_TYPE_POINTER_MOVE
, pointer1
, 5, 5));
393 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
395 // Respond with 1,2 for pointer1 (nothing chosen yet).
396 SetGestures(&child_
, pointer1
, kInvalidGestureId
, SetWith(1u, 2u),
397 std::set
<uint32_t>());
398 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
399 gesture_delegate_
.GetAndClearDescriptions());
401 // Respond with 1,2 and choose 1 for pointer2. This results in the following:
402 // down for pointer 1 (because we chose a gesture in common with pointer1),
403 // move for pointer 1 in both connections (because a gesture was chosen queued
404 // up events are sent), down for pointer2 for the root and finally
405 // notification of what was chosen.
406 SetGestures(&child_
, pointer2
, 1u, SetWith(1u, 2u), std::set
<uint32_t>());
407 ASSERT_EQ(5u, gesture_delegate_
.descriptions().size());
408 EXPECT_EQ("down pointer=1 connection=1 chosen=true",
409 gesture_delegate_
.descriptions()[0]);
410 EXPECT_EQ("move pointer=1 connection=2 chosen=true",
411 gesture_delegate_
.descriptions()[1]);
412 EXPECT_EQ("move pointer=1 connection=1 chosen=true",
413 gesture_delegate_
.descriptions()[2]);
414 EXPECT_EQ("down pointer=2 connection=1 chosen=true",
415 gesture_delegate_
.descriptions()[3]);
416 EXPECT_EQ("connection=2 chosen=1 canceled=2",
417 gesture_delegate_
.descriptions()[4]);
420 TEST_F(GestureManagerTest
, TwoViewsSingleGestureUp
) {
423 const int32_t pointer_id
= 1;
424 gesture_manager_
.ProcessEvent(
425 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
426 // Deepest child should be queried first.
427 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
428 gesture_delegate_
.GetAndClearDescriptions());
430 // Send an up, shouldn't result in anything.
431 gesture_manager_
.ProcessEvent(
432 *CreateEvent(mojo::EVENT_TYPE_POINTER_UP
, pointer_id
, 5, 5));
433 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
435 // Respond from the first view, with a chosen gesture.
436 SetGestures(&child_
, pointer_id
, 5u, SetWith(5u, 10u), std::set
<uint32_t>());
437 ASSERT_EQ(4u, gesture_delegate_
.descriptions().size());
438 EXPECT_EQ("down pointer=1 connection=1 chosen=true",
439 gesture_delegate_
.descriptions()[0]);
440 EXPECT_EQ("up pointer=1 connection=2 chosen=true",
441 gesture_delegate_
.descriptions()[1]);
442 EXPECT_EQ("up pointer=1 connection=1 chosen=true",
443 gesture_delegate_
.descriptions()[2]);
444 EXPECT_EQ("connection=2 chosen=5 canceled=10",
445 gesture_delegate_
.descriptions()[3]);
448 TEST_F(GestureManagerTest
, SingleViewSingleGestureCancel
) {
449 const int32_t pointer_id
= 1;
450 gesture_manager_
.ProcessEvent(
451 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
452 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
453 gesture_delegate_
.GetAndClearDescriptions());
455 // Send a cancel, shouldn't result in anything.
456 gesture_manager_
.ProcessEvent(
457 *CreateEvent(mojo::EVENT_TYPE_POINTER_CANCEL
, pointer_id
, 5, 5));
458 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
460 // Respond from the first view, with no gesture, should unblock cancel.
461 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
462 std::set
<uint32_t>());
463 EXPECT_EQ("cancel pointer=1 connection=1 chosen=false",
464 gesture_delegate_
.GetAndClearDescriptions());
467 } // namespace view_manager