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 view_delegate_
.set_root_view(&root_
);
153 root_
.SetVisible(true);
154 MarkAsRespondsToTouch(&root_
);
155 root_
.SetBounds(gfx::Rect(0, 0, 100, 100));
157 ~GestureManagerTest() override
{}
159 void SetGestures(const ServerView
* view
,
161 uint32_t chosen_gesture_id
,
162 const std::set
<uint32_t>& possible_gesture_ids
,
163 const std::set
<uint32_t>& canceled_ids
) {
164 scoped_ptr
<ChangeMap
> result(
165 gesture_manager_
.SetGestures(view
, pointer_id
, chosen_gesture_id
,
166 possible_gesture_ids
, canceled_ids
));
167 gesture_delegate_
.AppendDescriptionsFromResults(*result
);
170 void AddChildView() {
171 MarkAsRespondsToTouch(&child_
);
172 child_
.SetVisible(true);
174 child_
.SetBounds(gfx::Rect(0, 0, 100, 100));
178 TestServerViewDelegate view_delegate_
;
181 TestGestureManagerDelegate gesture_delegate_
;
182 GestureManager gesture_manager_
;
185 DISALLOW_COPY_AND_ASSIGN(GestureManagerTest
);
188 TEST_F(GestureManagerTest
, SingleViewAndSingleGesture
) {
189 const int32_t pointer_id
= 1;
190 gesture_manager_
.ProcessEvent(
191 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
192 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
193 gesture_delegate_
.GetAndClearDescriptions());
195 // Choose this pointer.
196 SetGestures(&root_
, pointer_id
, 10u, SetWith(10u), std::set
<uint32_t>());
197 EXPECT_EQ("connection=1 chosen=10",
198 gesture_delegate_
.GetAndClearDescriptions());
201 TEST_F(GestureManagerTest
, SingleViewAndTwoGestures
) {
202 const int32_t pointer_id
= 1;
203 gesture_manager_
.ProcessEvent(
204 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
205 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
206 gesture_delegate_
.GetAndClearDescriptions());
208 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
209 std::set
<uint32_t>());
211 // Delegate should have got nothing.
212 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
214 // Cancel 10, 5 should become active.
215 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
218 EXPECT_EQ("connection=1 chosen=5 canceled=10",
219 gesture_delegate_
.GetAndClearDescriptions());
222 TEST_F(GestureManagerTest
, TwoViewsSingleGesture
) {
225 const int32_t pointer_id
= 1;
226 gesture_manager_
.ProcessEvent(
227 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
228 // Deepest child should be queried first.
229 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
230 gesture_delegate_
.GetAndClearDescriptions());
232 // Respond from the first view, which triggers the second to be queried.
233 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
234 std::set
<uint32_t>());
235 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
236 gesture_delegate_
.GetAndClearDescriptions());
238 // Respond with 5,10 for the second view. Should get nothing.
239 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
240 std::set
<uint32_t>());
241 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
243 // Cancel 10 in the child.
244 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
246 EXPECT_EQ("connection=2 canceled=10",
247 gesture_delegate_
.GetAndClearDescriptions());
249 // Choose 5 in the root. This should choose 5 in the root and cancel 5 in
251 SetGestures(&root_
, pointer_id
, 5u, SetWith(5u, 10u), SetWith(10u));
252 ASSERT_EQ(2u, gesture_delegate_
.descriptions().size());
253 EXPECT_EQ("connection=1 chosen=5 canceled=10",
254 gesture_delegate_
.descriptions()[0]);
255 EXPECT_EQ("connection=2 canceled=5", gesture_delegate_
.descriptions()[1]);
258 TEST_F(GestureManagerTest
, TwoViewsWaitForMoveToChoose
) {
261 const int32_t pointer_id
= 1;
262 gesture_manager_
.ProcessEvent(
263 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
264 // Deepest child should be queried first.
265 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
266 gesture_delegate_
.GetAndClearDescriptions());
268 // Send a move. The move should not be processed as GestureManager is
269 // still waiting for responses.
270 gesture_manager_
.ProcessEvent(
271 *CreateEvent(mojo::EVENT_TYPE_POINTER_MOVE
, pointer_id
, 6, 6));
272 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
274 // Respond from the first view, which triggers the second to be queried.
275 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
276 std::set
<uint32_t>());
277 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
278 gesture_delegate_
.GetAndClearDescriptions());
280 // Respond with 1,2 for the second view.
281 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(1u, 2u),
282 std::set
<uint32_t>());
283 // Now that we've responded to the down requests we should get a move for the
285 EXPECT_EQ("move pointer=1 connection=2 chosen=false",
286 gesture_delegate_
.GetAndClearDescriptions());
288 // Respond for the child, root should now get move.
289 SetGestures(&child_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
290 std::set
<uint32_t>());
291 EXPECT_EQ("move pointer=1 connection=1 chosen=false",
292 gesture_delegate_
.GetAndClearDescriptions());
294 // Respond with nothing chosen for the root. Nothing should come in as no
296 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(1u, 2u),
297 std::set
<uint32_t>());
298 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
300 // Send another move event and respond with a chosen id.
301 gesture_manager_
.ProcessEvent(
302 *CreateEvent(mojo::EVENT_TYPE_POINTER_MOVE
, pointer_id
, 7, 7));
303 EXPECT_EQ("move pointer=1 connection=2 chosen=false",
304 gesture_delegate_
.GetAndClearDescriptions());
305 SetGestures(&child_
, pointer_id
, 5u, SetWith(5u, 10u), std::set
<uint32_t>());
306 ASSERT_EQ(3u, gesture_delegate_
.descriptions().size());
307 // Now that a gesture is chosen the move event is generated.
308 EXPECT_EQ("move pointer=1 connection=1 chosen=true",
309 gesture_delegate_
.descriptions()[0]);
310 EXPECT_EQ("connection=1 canceled=1,2", gesture_delegate_
.descriptions()[1]);
311 EXPECT_EQ("connection=2 chosen=5 canceled=10",
312 gesture_delegate_
.descriptions()[2]);
315 TEST_F(GestureManagerTest
, SingleViewNewPointerAfterChoose
) {
316 const int32_t pointer_id
= 1;
317 gesture_manager_
.ProcessEvent(
318 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
319 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
320 gesture_delegate_
.GetAndClearDescriptions());
323 SetGestures(&root_
, pointer_id
, 5u, SetWith(5u, 10u), std::set
<uint32_t>());
324 EXPECT_EQ("connection=1 chosen=5 canceled=10",
325 gesture_delegate_
.GetAndClearDescriptions());
327 // Start another down event with a different pointer.
328 const int32_t pointer_id2
= 2;
329 gesture_manager_
.ProcessEvent(
330 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id2
, 5, 5));
331 EXPECT_EQ("down pointer=2 connection=1 chosen=false",
332 gesture_delegate_
.GetAndClearDescriptions());
334 // For the new pointer supply the id of a gesture that has been chosen.
335 // Even though we didn't explicitly supply 5 as chosen, 5 is chosen because
336 // it's already in the chosen state for pointer 1.
337 SetGestures(&root_
, pointer_id2
, kInvalidGestureId
, SetWith(5u, 11u),
338 std::set
<uint32_t>());
339 EXPECT_EQ("connection=1 chosen=5 canceled=11",
340 gesture_delegate_
.GetAndClearDescriptions());
343 TEST_F(GestureManagerTest
, SingleViewChoosingConflictingGestures
) {
344 // For pointer1 choose 1 with 1,2,3 as possibilities.
345 const int32_t pointer1
= 1;
346 gesture_manager_
.ProcessEvent(
347 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer1
, 5, 5));
348 gesture_delegate_
.GetAndClearDescriptions();
349 SetGestures(&root_
, pointer1
, 1u, SetWith(1u, 2u, 3u), std::set
<uint32_t>());
350 EXPECT_EQ("connection=1 chosen=1 canceled=2,3",
351 gesture_delegate_
.GetAndClearDescriptions());
353 // For pointer2 choose 11 with 11,12 as possibilities.
354 const int32_t pointer2
= 2;
355 gesture_manager_
.ProcessEvent(
356 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer2
, 5, 5));
357 gesture_delegate_
.GetAndClearDescriptions();
358 SetGestures(&root_
, pointer2
, 11u, SetWith(11u, 12u), std::set
<uint32_t>());
359 EXPECT_EQ("connection=1 chosen=11 canceled=12",
360 gesture_delegate_
.GetAndClearDescriptions());
362 // For pointer3 choose 21 with 1,11,21 as possibilties.
363 const int32_t pointer3
= 3;
364 gesture_manager_
.ProcessEvent(
365 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer3
, 5, 5));
366 gesture_delegate_
.GetAndClearDescriptions();
367 SetGestures(&root_
, pointer3
, 21u, SetWith(1u, 11u, 21u),
368 std::set
<uint32_t>());
369 EXPECT_EQ("connection=1 chosen=21 canceled=1,11",
370 gesture_delegate_
.GetAndClearDescriptions());
373 TEST_F(GestureManagerTest
,
374 TwoViewsRespondingWithChosenGestureSendsRemainingEvents
) {
377 // Start two pointer downs, don't respond to either.
378 const int32_t pointer1
= 1;
379 gesture_manager_
.ProcessEvent(
380 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer1
, 5, 5));
381 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
382 gesture_delegate_
.GetAndClearDescriptions());
384 const int32_t pointer2
= 2;
385 gesture_manager_
.ProcessEvent(
386 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer2
, 5, 5));
387 EXPECT_EQ("down pointer=2 connection=2 chosen=false",
388 gesture_delegate_
.GetAndClearDescriptions());
390 // Queue up a move event for pointer1. The event should not be forwarded
391 // as we're still waiting.
392 gesture_manager_
.ProcessEvent(
393 *CreateEvent(mojo::EVENT_TYPE_POINTER_MOVE
, pointer1
, 5, 5));
394 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
396 // Respond with 1,2 for pointer1 (nothing chosen yet).
397 SetGestures(&child_
, pointer1
, kInvalidGestureId
, SetWith(1u, 2u),
398 std::set
<uint32_t>());
399 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
400 gesture_delegate_
.GetAndClearDescriptions());
402 // Respond with 1,2 and choose 1 for pointer2. This results in the following:
403 // down for pointer 1 (because we chose a gesture in common with pointer1),
404 // move for pointer 1 in both connections (because a gesture was chosen queued
405 // up events are sent), down for pointer2 for the root and finally
406 // notification of what was chosen.
407 SetGestures(&child_
, pointer2
, 1u, SetWith(1u, 2u), std::set
<uint32_t>());
408 ASSERT_EQ(5u, gesture_delegate_
.descriptions().size());
409 EXPECT_EQ("down pointer=1 connection=1 chosen=true",
410 gesture_delegate_
.descriptions()[0]);
411 EXPECT_EQ("move pointer=1 connection=2 chosen=true",
412 gesture_delegate_
.descriptions()[1]);
413 EXPECT_EQ("move pointer=1 connection=1 chosen=true",
414 gesture_delegate_
.descriptions()[2]);
415 EXPECT_EQ("down pointer=2 connection=1 chosen=true",
416 gesture_delegate_
.descriptions()[3]);
417 EXPECT_EQ("connection=2 chosen=1 canceled=2",
418 gesture_delegate_
.descriptions()[4]);
421 TEST_F(GestureManagerTest
, TwoViewsSingleGestureUp
) {
424 const int32_t pointer_id
= 1;
425 gesture_manager_
.ProcessEvent(
426 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
427 // Deepest child should be queried first.
428 EXPECT_EQ("down pointer=1 connection=2 chosen=false",
429 gesture_delegate_
.GetAndClearDescriptions());
431 // Send an up, shouldn't result in anything.
432 gesture_manager_
.ProcessEvent(
433 *CreateEvent(mojo::EVENT_TYPE_POINTER_UP
, pointer_id
, 5, 5));
434 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
436 // Respond from the first view, with a chosen gesture.
437 SetGestures(&child_
, pointer_id
, 5u, SetWith(5u, 10u), std::set
<uint32_t>());
438 ASSERT_EQ(4u, gesture_delegate_
.descriptions().size());
439 EXPECT_EQ("down pointer=1 connection=1 chosen=true",
440 gesture_delegate_
.descriptions()[0]);
441 EXPECT_EQ("up pointer=1 connection=2 chosen=true",
442 gesture_delegate_
.descriptions()[1]);
443 EXPECT_EQ("up pointer=1 connection=1 chosen=true",
444 gesture_delegate_
.descriptions()[2]);
445 EXPECT_EQ("connection=2 chosen=5 canceled=10",
446 gesture_delegate_
.descriptions()[3]);
449 TEST_F(GestureManagerTest
, SingleViewSingleGestureCancel
) {
450 const int32_t pointer_id
= 1;
451 gesture_manager_
.ProcessEvent(
452 *CreateEvent(mojo::EVENT_TYPE_POINTER_DOWN
, pointer_id
, 5, 5));
453 EXPECT_EQ("down pointer=1 connection=1 chosen=false",
454 gesture_delegate_
.GetAndClearDescriptions());
456 // Send a cancel, shouldn't result in anything.
457 gesture_manager_
.ProcessEvent(
458 *CreateEvent(mojo::EVENT_TYPE_POINTER_CANCEL
, pointer_id
, 5, 5));
459 EXPECT_EQ(std::string(), gesture_delegate_
.GetAndClearDescriptions());
461 // Respond from the first view, with no gesture, should unblock cancel.
462 SetGestures(&root_
, pointer_id
, kInvalidGestureId
, SetWith(5u, 10u),
463 std::set
<uint32_t>());
464 EXPECT_EQ("cancel pointer=1 connection=1 chosen=false",
465 gesture_delegate_
.GetAndClearDescriptions());
468 } // namespace view_manager