touch_observer_hud_unittest.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright (c) 2013 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.
4
5#include "ash/touch/touch_observer_hud.h"
6
7#include "ash/ash_switches.h"
8#include "ash/display/display_manager.h"
9#include "ash/root_window_controller.h"
10#include "ash/screen_util.h"
11#include "ash/shell.h"
12#include "ash/test/ash_test_base.h"
13#include "ash/test/display_manager_test_api.h"
14#include "ash/touch/touch_hud_debug.h"
15#include "ash/touch/touch_hud_projection.h"
16#include "base/command_line.h"
17#include "base/format_macros.h"
18#include "base/strings/stringprintf.h"
19#include "ui/aura/window.h"
20
21namespace ash {
22
23class TouchHudTestBase : public test::AshTestBase {
24 public:
25  TouchHudTestBase() {}
26  virtual ~TouchHudTestBase() {}
27
28  virtual void SetUp() OVERRIDE {
29    test::AshTestBase::SetUp();
30
31    // Initialize display infos. They should be initialized after Ash
32    // environment is set up, i.e., after test::AshTestBase::SetUp().
33    internal_display_id_ = test::DisplayManagerTestApi(GetDisplayManager()).
34        SetFirstDisplayAsInternalDisplay();
35    external_display_id_ = 10;
36    mirrored_display_id_ = 11;
37
38    internal_display_info_ =
39        CreateDisplayInfo(internal_display_id_, gfx::Rect(0, 0, 500, 500));
40    external_display_info_ =
41        CreateDisplayInfo(external_display_id_, gfx::Rect(1, 1, 100, 100));
42    mirrored_display_info_ =
43        CreateDisplayInfo(mirrored_display_id_, gfx::Rect(0, 0, 100, 100));
44  }
45
46  gfx::Display GetPrimaryDisplay() {
47    return Shell::GetScreen()->GetPrimaryDisplay();
48  }
49
50  const gfx::Display& GetSecondaryDisplay() {
51    return ScreenUtil::GetSecondaryDisplay();
52  }
53
54  void SetupSingleDisplay() {
55    display_info_list_.clear();
56    display_info_list_.push_back(internal_display_info_);
57    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
58  }
59
60  void SetupDualDisplays() {
61    display_info_list_.clear();
62    display_info_list_.push_back(internal_display_info_);
63    display_info_list_.push_back(external_display_info_);
64    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
65  }
66
67  void SetInternalAsPrimary() {
68    const gfx::Display& internal_display =
69        GetDisplayManager()->GetDisplayForId(internal_display_id_);
70    GetDisplayController()->SetPrimaryDisplay(internal_display);
71  }
72
73  void SetExternalAsPrimary() {
74    const gfx::Display& external_display =
75        GetDisplayManager()->GetDisplayForId(external_display_id_);
76    GetDisplayController()->SetPrimaryDisplay(external_display);
77  }
78
79  void MirrorDisplays() {
80    DCHECK_EQ(2U, display_info_list_.size());
81    DCHECK_EQ(internal_display_id_, display_info_list_[0].id());
82    DCHECK_EQ(external_display_id_, display_info_list_[1].id());
83    display_info_list_[1] = mirrored_display_info_;
84    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
85  }
86
87  void UnmirrorDisplays() {
88    DCHECK_EQ(2U, display_info_list_.size());
89    DCHECK_EQ(internal_display_id_, display_info_list_[0].id());
90    DCHECK_EQ(mirrored_display_id_, display_info_list_[1].id());
91    display_info_list_[1] = external_display_info_;
92    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
93  }
94
95  void RemoveInternalDisplay() {
96    DCHECK_LT(0U, display_info_list_.size());
97    DCHECK_EQ(internal_display_id_, display_info_list_[0].id());
98    display_info_list_.erase(display_info_list_.begin());
99    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
100  }
101
102  void RemoveExternalDisplay() {
103    DCHECK_EQ(2U, display_info_list_.size());
104    display_info_list_.pop_back();
105    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
106  }
107
108  void AddInternalDisplay() {
109    DCHECK_EQ(0U, display_info_list_.size());
110    display_info_list_.push_back(internal_display_info_);
111    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
112  }
113
114  void AddExternalDisplay() {
115    DCHECK_EQ(1U, display_info_list_.size());
116    display_info_list_.push_back(external_display_info_);
117    GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
118  }
119
120  int64 internal_display_id() const {
121    return internal_display_id_;
122  }
123
124  int64 external_display_id() const {
125    return external_display_id_;
126  }
127
128 protected:
129  DisplayManager* GetDisplayManager() {
130    return Shell::GetInstance()->display_manager();
131  }
132
133  DisplayController* GetDisplayController() {
134    return Shell::GetInstance()->display_controller();
135  }
136
137  const gfx::Display& GetInternalDisplay() {
138    return GetDisplayManager()->GetDisplayForId(internal_display_id_);
139  }
140
141  const gfx::Display& GetExternalDisplay() {
142    return GetDisplayManager()->GetDisplayForId(external_display_id_);
143  }
144
145  aura::Window* GetInternalRootWindow() {
146    return GetDisplayController()->GetRootWindowForDisplayId(
147        internal_display_id_);
148  }
149
150  aura::Window* GetExternalRootWindow() {
151    return GetDisplayController()->GetRootWindowForDisplayId(
152        external_display_id_);
153  }
154
155  aura::Window* GetPrimaryRootWindow() {
156    const gfx::Display& display = GetPrimaryDisplay();
157    return GetDisplayController()->GetRootWindowForDisplayId(display.id());
158  }
159
160  aura::Window* GetSecondaryRootWindow() {
161    const gfx::Display& display = GetSecondaryDisplay();
162    return GetDisplayController()->GetRootWindowForDisplayId(display.id());
163  }
164
165  RootWindowController* GetInternalRootController() {
166    aura::Window* root = GetInternalRootWindow();
167    return GetRootWindowController(root);
168  }
169
170  RootWindowController* GetExternalRootController() {
171    aura::Window* root = GetExternalRootWindow();
172    return GetRootWindowController(root);
173  }
174
175  RootWindowController* GetPrimaryRootController() {
176    aura::Window* root = GetPrimaryRootWindow();
177    return GetRootWindowController(root);
178  }
179
180  RootWindowController* GetSecondaryRootController() {
181    aura::Window* root = GetSecondaryRootWindow();
182    return GetRootWindowController(root);
183  }
184
185  DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) {
186    DisplayInfo info(id, base::StringPrintf("x-%" PRId64, id), false);
187    info.SetBounds(bounds);
188    return info;
189  }
190
191  aura::Window* GetRootWindowForTouchHud(TouchObserverHUD* hud) {
192    return hud->root_window_;
193  }
194
195  views::Widget* GetWidgetForTouchHud(TouchObserverHUD* hud) {
196    return hud->widget_;
197  }
198
199  int64 internal_display_id_;
200  int64 external_display_id_;
201  int64 mirrored_display_id_;
202  DisplayInfo internal_display_info_;
203  DisplayInfo external_display_info_;
204  DisplayInfo mirrored_display_info_;
205
206  std::vector<DisplayInfo> display_info_list_;
207
208  DISALLOW_COPY_AND_ASSIGN(TouchHudTestBase);
209};
210
211class TouchHudDebugTest : public TouchHudTestBase {
212 public:
213  TouchHudDebugTest() {}
214  virtual ~TouchHudDebugTest() {}
215
216  virtual void SetUp() OVERRIDE {
217    // Add ash-touch-hud flag to enable debug touch HUD. This flag should be set
218    // before Ash environment is set up, i.e., before TouchHudTestBase::SetUp().
219    CommandLine::ForCurrentProcess()->AppendSwitch(
220        ash::switches::kAshTouchHud);
221
222    TouchHudTestBase::SetUp();
223  }
224
225  void CheckInternalDisplay() {
226    EXPECT_NE(static_cast<TouchObserverHUD*>(NULL), GetInternalTouchHudDebug());
227    EXPECT_EQ(internal_display_id(), GetInternalTouchHudDebug()->display_id());
228    EXPECT_EQ(GetInternalRootWindow(),
229              GetRootWindowForTouchHud(GetInternalTouchHudDebug()));
230    EXPECT_EQ(GetInternalRootWindow(),
231              GetWidgetForTouchHud(GetInternalTouchHudDebug())->
232                  GetNativeView()->GetRootWindow());
233    EXPECT_EQ(GetInternalDisplay().size(),
234              GetWidgetForTouchHud(GetInternalTouchHudDebug())->
235                  GetWindowBoundsInScreen().size());
236  }
237
238  void CheckExternalDisplay() {
239    EXPECT_NE(static_cast<TouchHudDebug*>(NULL), GetExternalTouchHudDebug());
240    EXPECT_EQ(external_display_id(), GetExternalTouchHudDebug()->display_id());
241    EXPECT_EQ(GetExternalRootWindow(),
242              GetRootWindowForTouchHud(GetExternalTouchHudDebug()));
243    EXPECT_EQ(GetExternalRootWindow(),
244              GetWidgetForTouchHud(GetExternalTouchHudDebug())->
245                  GetNativeView()->GetRootWindow());
246    EXPECT_EQ(GetExternalDisplay().size(),
247              GetWidgetForTouchHud(GetExternalTouchHudDebug())->
248                  GetWindowBoundsInScreen().size());
249  }
250
251 private:
252  TouchHudDebug* GetInternalTouchHudDebug() {
253    return GetInternalRootController()->touch_hud_debug();
254  }
255
256  TouchHudDebug* GetExternalTouchHudDebug() {
257    return GetExternalRootController()->touch_hud_debug();
258  }
259
260  TouchHudDebug* GetPrimaryTouchHudDebug() {
261    return GetPrimaryRootController()->touch_hud_debug();
262  }
263
264  TouchHudDebug* GetSecondaryTouchHudDebug() {
265    return GetSecondaryRootController()->touch_hud_debug();
266  }
267
268  DISALLOW_COPY_AND_ASSIGN(TouchHudDebugTest);
269};
270
271class TouchHudProjectionTest : public TouchHudTestBase {
272 public:
273  TouchHudProjectionTest() {}
274  virtual ~TouchHudProjectionTest() {}
275
276  void EnableTouchHudProjection() {
277    Shell::GetInstance()->SetTouchHudProjectionEnabled(true);
278  }
279
280  void DisableTouchHudProjection() {
281    Shell::GetInstance()->SetTouchHudProjectionEnabled(false);
282  }
283
284  TouchHudProjection* GetInternalTouchHudProjection() {
285    return GetInternalRootController()->touch_hud_projection();
286  }
287
288  int GetInternalTouchPointsCount() {
289    return GetInternalTouchHudProjection()->points_.size();
290  }
291
292  void SendTouchEventToInternalHud(ui::EventType type,
293                                   const gfx::Point& location,
294                                   int touch_id) {
295    ui::TouchEvent event(type, location, touch_id, event_time);
296    GetInternalTouchHudProjection()->OnTouchEvent(&event);
297
298    // Advance time for next event.
299    event_time += base::TimeDelta::FromMilliseconds(100);
300  }
301
302 private:
303  base::TimeDelta event_time;
304
305  DISALLOW_COPY_AND_ASSIGN(TouchHudProjectionTest);
306};
307
308// Checks if debug touch HUD is correctly initialized for a single display.
309TEST_F(TouchHudDebugTest, SingleDisplay) {
310  // Setup a single display setting.
311  SetupSingleDisplay();
312
313  // Check if touch HUD is set correctly and associated with appropriate
314  // display.
315  CheckInternalDisplay();
316}
317
318// Checks if debug touch HUDs are correctly initialized for two displays.
319TEST_F(TouchHudDebugTest, DualDisplays) {
320  if (!SupportsMultipleDisplays())
321    return;
322
323  // Setup a dual display setting.
324  SetupDualDisplays();
325
326  // Check if touch HUDs are set correctly and associated with appropriate
327  // displays.
328  CheckInternalDisplay();
329  CheckExternalDisplay();
330}
331
332// Checks if debug touch HUDs are correctly handled when primary display is
333// changed.
334TEST_F(TouchHudDebugTest, SwapPrimaryDisplay) {
335  if (!SupportsMultipleDisplays())
336    return;
337
338  // Setup a dual display setting.
339  SetupDualDisplays();
340
341  // Set the primary display to the external one.
342  SetExternalAsPrimary();
343
344  // Check if displays' touch HUDs are not swapped as root windows are.
345  EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id());
346  EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id());
347  CheckInternalDisplay();
348  CheckExternalDisplay();
349
350  // Set the primary display back to the internal one.
351  SetInternalAsPrimary();
352
353  // Check if displays' touch HUDs are not swapped back as root windows are.
354  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
355  EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id());
356  CheckInternalDisplay();
357  CheckExternalDisplay();
358}
359
360// Checks if debug touch HUDs are correctly handled when displays are mirrored.
361TEST_F(TouchHudDebugTest, MirrorDisplays) {
362  if (!SupportsMultipleDisplays())
363    return;
364
365  // Setup a dual display setting.
366  SetupDualDisplays();
367
368  // Mirror displays.
369  MirrorDisplays();
370
371  // Check if the internal display is intact.
372  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
373  CheckInternalDisplay();
374
375  // Unmirror displays.
376  UnmirrorDisplays();
377
378  // Check if external display is added back correctly.
379  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
380  EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id());
381  CheckInternalDisplay();
382  CheckExternalDisplay();
383}
384
385// Checks if debug touch HUDs are correctly handled when displays are mirrored
386// after setting the external display as the primary one.
387TEST_F(TouchHudDebugTest, SwapPrimaryThenMirrorDisplays) {
388  if (!SupportsMultipleDisplays())
389    return;
390
391  // Setup a dual display setting.
392  SetupDualDisplays();
393
394  // Set the primary display to the external one.
395  SetExternalAsPrimary();
396
397  // Mirror displays.
398  MirrorDisplays();
399
400  // Check if the internal display is set as the primary one.
401  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
402  CheckInternalDisplay();
403
404  // Unmirror displays.
405  UnmirrorDisplays();
406
407  // Check if the external display is added back as the primary display and
408  // touch HUDs are set correctly.
409  EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id());
410  EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id());
411  CheckInternalDisplay();
412  CheckExternalDisplay();
413}
414
415// Checks if debug touch HUDs are correctly handled when the external display,
416// which is the secondary one, is removed.
417TEST_F(TouchHudDebugTest, RemoveSecondaryDisplay) {
418  if (!SupportsMultipleDisplays())
419    return;
420
421  // Setup a dual display setting.
422  SetupDualDisplays();
423
424  // Remove external display which is the secondary one.
425  RemoveExternalDisplay();
426
427  // Check if the internal display is intact.
428  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
429  CheckInternalDisplay();
430
431  // Add external display back.
432  AddExternalDisplay();
433
434  // Check if displays' touch HUDs are set correctly.
435  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
436  EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id());
437  CheckInternalDisplay();
438  CheckExternalDisplay();
439}
440
441// Checks if debug touch HUDs are correctly handled when the external display,
442// which is set as the primary display, is removed.
443TEST_F(TouchHudDebugTest, RemovePrimaryDisplay) {
444  if (!SupportsMultipleDisplays())
445    return;
446
447  // Setup a dual display setting.
448  SetupDualDisplays();
449
450  // Set the primary display to the external one.
451  SetExternalAsPrimary();
452
453  // Remove the external display which is the primary display.
454  RemoveExternalDisplay();
455
456  // Check if the internal display is set as the primary one.
457  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
458  CheckInternalDisplay();
459
460  // Add the external display back.
461  AddExternalDisplay();
462
463  // Check if the external display is set as primary and touch HUDs are set
464  // correctly.
465  EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id());
466  EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id());
467  CheckInternalDisplay();
468  CheckExternalDisplay();
469}
470
471// Checks if debug touch HUDs are correctly handled when all displays are
472// removed.
473TEST_F(TouchHudDebugTest, Headless) {
474  if (!SupportsMultipleDisplays())
475    return;
476
477  // Setup a single display setting.
478  SetupSingleDisplay();
479
480  // Remove the only display which is the internal one.
481  RemoveInternalDisplay();
482
483  // Add the internal display back.
484  AddInternalDisplay();
485
486  // Check if the display's touch HUD is set correctly.
487  EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
488  CheckInternalDisplay();
489}
490
491// Checks projection touch HUD with a sequence of touch-pressed, touch-moved,
492// and touch-released events.
493TEST_F(TouchHudProjectionTest, TouchMoveRelease) {
494  SetupSingleDisplay();
495  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
496
497  EnableTouchHudProjection();
498  EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
499            GetInternalTouchHudProjection());
500  EXPECT_EQ(0, GetInternalTouchPointsCount());
501
502  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
503  EXPECT_EQ(1, GetInternalTouchPointsCount());
504
505  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
506  EXPECT_EQ(1, GetInternalTouchPointsCount());
507
508  SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1);
509  EXPECT_EQ(0, GetInternalTouchPointsCount());
510
511  // Disabling projection touch HUD shoud remove it without crashing.
512  DisableTouchHudProjection();
513  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
514}
515
516// Checks projection touch HUD with a sequence of touch-pressed, touch-moved,
517// and touch-cancelled events.
518TEST_F(TouchHudProjectionTest, TouchMoveCancel) {
519  SetupSingleDisplay();
520  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
521
522  EnableTouchHudProjection();
523  EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
524            GetInternalTouchHudProjection());
525  EXPECT_EQ(0, GetInternalTouchPointsCount());
526
527  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
528  EXPECT_EQ(1, GetInternalTouchPointsCount());
529
530  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
531  EXPECT_EQ(1, GetInternalTouchPointsCount());
532
533  SendTouchEventToInternalHud(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 20), 1);
534  EXPECT_EQ(0, GetInternalTouchPointsCount());
535
536  // Disabling projection touch HUD shoud remove it without crashing.
537  DisableTouchHudProjection();
538  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
539}
540
541// Checks projection touch HUD with two simultaneous touches.
542TEST_F(TouchHudProjectionTest, DoubleTouch) {
543  SetupSingleDisplay();
544  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
545
546  EnableTouchHudProjection();
547  EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
548            GetInternalTouchHudProjection());
549  EXPECT_EQ(0, GetInternalTouchPointsCount());
550
551  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
552  EXPECT_EQ(1, GetInternalTouchPointsCount());
553
554  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(20, 10), 2);
555  EXPECT_EQ(2, GetInternalTouchPointsCount());
556
557  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
558  EXPECT_EQ(2, GetInternalTouchPointsCount());
559
560  SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 2);
561  EXPECT_EQ(2, GetInternalTouchPointsCount());
562
563  SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1);
564  EXPECT_EQ(1, GetInternalTouchPointsCount());
565
566  SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 2);
567  EXPECT_EQ(0, GetInternalTouchPointsCount());
568
569  // Disabling projection touch HUD shoud remove it without crashing.
570  DisableTouchHudProjection();
571  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
572}
573
574// Checks if turning off touch HUD projection while touching the screen is
575// handled correctly.
576TEST_F(TouchHudProjectionTest, DisableWhileTouching) {
577  SetupSingleDisplay();
578  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
579
580  EnableTouchHudProjection();
581  EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
582            GetInternalTouchHudProjection());
583  EXPECT_EQ(0, GetInternalTouchPointsCount());
584
585  SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
586  EXPECT_EQ(1, GetInternalTouchPointsCount());
587
588  // Disabling projection touch HUD shoud remove it without crashing.
589  DisableTouchHudProjection();
590  EXPECT_EQ(NULL, GetInternalTouchHudProjection());
591}
592
593}  // namespace ash
594