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