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/display/mirror_window_controller.h"
6
7#include "ash/ash_switches.h"
8#include "ash/display/display_manager.h"
9#include "ash/shell.h"
10#include "ash/test/ash_test_base.h"
11#include "ash/test/display_manager_test_api.h"
12#include "ash/test/mirror_window_test_api.h"
13#include "base/command_line.h"
14#include "base/strings/stringprintf.h"
15#include "ui/aura/test/test_window_delegate.h"
16#include "ui/aura/test/test_windows.h"
17#include "ui/aura/window.h"
18#include "ui/aura/window_event_dispatcher.h"
19#include "ui/base/hit_test.h"
20#include "ui/events/test/event_generator.h"
21
22namespace ash {
23
24namespace {
25DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) {
26  DisplayInfo info(id, base::StringPrintf("x-%d", static_cast<int>(id)), false);
27  info.SetBounds(bounds);
28  return info;
29}
30
31class MirrorOnBootTest : public test::AshTestBase {
32 public:
33  MirrorOnBootTest() {}
34  virtual ~MirrorOnBootTest() {}
35
36  virtual void SetUp() OVERRIDE {
37    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
38        switches::kAshHostWindowBounds, "1+1-300x300,1+301-300x300");
39    CommandLine::ForCurrentProcess()->AppendSwitch(
40        switches::kAshEnableSoftwareMirroring);
41    test::AshTestBase::SetUp();
42  }
43  virtual void TearDown() OVERRIDE {
44    test::AshTestBase::TearDown();
45  }
46
47 private:
48  DISALLOW_COPY_AND_ASSIGN(MirrorOnBootTest);
49};
50
51}
52
53typedef test::AshTestBase MirrorWindowControllerTest;
54
55#if defined(OS_WIN)
56// Software mirroring does not work on win.
57#define MAYBE_MirrorCursorBasic DISABLED_MirrorCursorBasic
58#define MAYBE_MirrorCursorLocations DISABLED_MirrorCursorLocations
59#define MAYBE_MirrorCursorRotate DISABLED_MirrorCursorRotate
60#define MAYBE_DockMode DISABLED_DockMode
61#define MAYBE_MirrorOnBoot DISABLED_MirrorOnBoot
62#else
63#define MAYBE_MirrorCursorBasic MirrorCursorBasic
64#define MAYBE_MirrorCursorLocations MirrorCursorLocations
65#define MAYBE_MirrorCursorRotate MirrorCursorRotate
66#define MAYBE_DockMode DockMode
67#define MAYBE_MirrorOnBoot MirrorOnBoot
68#endif
69
70TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorBasic) {
71  test::MirrorWindowTestApi test_api;
72  aura::test::TestWindowDelegate test_window_delegate;
73  test_window_delegate.set_window_component(HTTOP);
74
75  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
76  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
77  UpdateDisplay("400x400,400x400");
78  aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
79  scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
80      &test_window_delegate,
81      0,
82      gfx::Rect(50, 50, 100, 100),
83      root));
84  window->Show();
85  window->SetName("foo");
86
87  EXPECT_TRUE(test_api.GetCursorWindow());
88  EXPECT_EQ("50,50 100x100", window->bounds().ToString());
89
90  ui::test::EventGenerator generator(root);
91  generator.MoveMouseTo(10, 10);
92
93  // Test if cursor movement is propertly reflected in mirror window.
94  gfx::Point hot_point = test_api.GetCursorHotPoint();
95  gfx::Point cursor_window_origin =
96      test_api.GetCursorWindow()->bounds().origin();
97  EXPECT_EQ("4,4", hot_point.ToString());
98  EXPECT_EQ(10 - hot_point.x(), cursor_window_origin.x());
99  EXPECT_EQ(10 - hot_point.y(), cursor_window_origin.y());
100  EXPECT_EQ(ui::kCursorNull, test_api.GetCurrentCursorType());
101  EXPECT_TRUE(test_api.GetCursorWindow()->IsVisible());
102
103  // Test if cursor type change is propertly reflected in mirror window.
104  generator.MoveMouseTo(100, 100);
105  hot_point = test_api.GetCursorHotPoint();
106  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
107  EXPECT_EQ(100 - hot_point.x(), cursor_window_origin.x());
108  EXPECT_EQ(100 - hot_point.y(), cursor_window_origin.y());
109  EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType());
110
111  // Test if visibility change is propertly reflected in mirror window.
112  // A key event hides cursor.
113  generator.PressKey(ui::VKEY_A, 0);
114  generator.ReleaseKey(ui::VKEY_A, 0);
115  EXPECT_FALSE(test_api.GetCursorWindow()->IsVisible());
116
117  // Mouse event makes it visible again.
118  generator.MoveMouseTo(300, 300);
119  hot_point = test_api.GetCursorHotPoint();
120  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
121  EXPECT_EQ(300 - hot_point.x(), cursor_window_origin.x());
122  EXPECT_EQ(300 - hot_point.y(), cursor_window_origin.y());
123  EXPECT_EQ(ui::kCursorNull, test_api.GetCurrentCursorType());
124  EXPECT_TRUE(test_api.GetCursorWindow()->IsVisible());
125}
126
127TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorRotate) {
128  test::MirrorWindowTestApi test_api;
129  aura::test::TestWindowDelegate test_window_delegate;
130  test_window_delegate.set_window_component(HTTOP);
131
132  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
133  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
134  UpdateDisplay("400x400,400x400");
135  aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
136  scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
137      &test_window_delegate,
138      0,
139      gfx::Rect(50, 50, 100, 100),
140      root));
141  window->Show();
142  window->SetName("foo");
143
144  EXPECT_TRUE(test_api.GetCursorWindow());
145  EXPECT_EQ("50,50 100x100", window->bounds().ToString());
146
147  ui::test::EventGenerator generator(root);
148  generator.MoveMouseToInHost(100, 100);
149
150  // Test if cursor movement is propertly reflected in mirror window.
151  gfx::Point hot_point = test_api.GetCursorHotPoint();
152  gfx::Point cursor_window_origin =
153      test_api.GetCursorWindow()->bounds().origin();
154  EXPECT_EQ("11,12", hot_point.ToString());
155  EXPECT_EQ(100 - hot_point.x(), cursor_window_origin.x());
156  EXPECT_EQ(100 - hot_point.y(), cursor_window_origin.y());
157  EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType());
158
159  UpdateDisplay("400x400/r,400x400");  // 90 degrees.
160  generator.MoveMouseToInHost(300, 100);
161  hot_point = test_api.GetCursorHotPoint();
162  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
163  EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType());
164  // The size of cursor image is 25x25, so the rotated hot point must
165  // be (25-12, 11).
166  EXPECT_EQ("13,11", hot_point.ToString());
167  EXPECT_EQ(300 - hot_point.x(), cursor_window_origin.x());
168  EXPECT_EQ(100 - hot_point.y(), cursor_window_origin.y());
169
170  UpdateDisplay("400x400/u,400x400");  // 180 degrees.
171  generator.MoveMouseToInHost(300, 300);
172  hot_point = test_api.GetCursorHotPoint();
173  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
174  EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType());
175  // Rotated hot point must be (25-11, 25-12).
176  EXPECT_EQ("14,13", hot_point.ToString());
177  EXPECT_EQ(300 - hot_point.x(), cursor_window_origin.x());
178  EXPECT_EQ(300 - hot_point.y(), cursor_window_origin.y());
179
180  UpdateDisplay("400x400/l,400x400");  // 270 degrees.
181  generator.MoveMouseToInHost(100, 300);
182  hot_point = test_api.GetCursorHotPoint();
183  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
184  EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType());
185  // Rotated hot point must be (12, 25-11).
186  EXPECT_EQ("12,14", hot_point.ToString());
187  EXPECT_EQ(100 - hot_point.x(), cursor_window_origin.x());
188  EXPECT_EQ(300 - hot_point.y(), cursor_window_origin.y());
189}
190
191// Make sure that the mirror cursor's location is same as
192// the source display's host location in the mirror root window's
193// coordinates.
194TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorLocations) {
195  test::MirrorWindowTestApi test_api;
196  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
197  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
198
199  // Test with device scale factor.
200  UpdateDisplay("400x600*2,400x600");
201
202  aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
203  ui::test::EventGenerator generator(root);
204  generator.MoveMouseToInHost(10, 20);
205
206  gfx::Point hot_point = test_api.GetCursorHotPoint();
207  EXPECT_EQ("8,9", hot_point.ToString());
208  gfx::Point cursor_window_origin =
209      test_api.GetCursorWindow()->bounds().origin();
210  EXPECT_EQ(10 - hot_point.x(), cursor_window_origin.x());
211  EXPECT_EQ(20 - hot_point.y(), cursor_window_origin.y());
212
213  // Test with ui scale
214  UpdateDisplay("400x600*0.5,400x600");
215  generator.MoveMouseToInHost(20, 30);
216
217  hot_point = test_api.GetCursorHotPoint();
218  EXPECT_EQ("4,4", hot_point.ToString());
219  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
220  EXPECT_EQ(20 - hot_point.x(), cursor_window_origin.x());
221  EXPECT_EQ(30 - hot_point.y(), cursor_window_origin.y());
222
223  // Test with rotation
224  UpdateDisplay("400x600/r,400x600");
225  generator.MoveMouseToInHost(30, 40);
226
227  hot_point = test_api.GetCursorHotPoint();
228  EXPECT_EQ("21,4", hot_point.ToString());
229  cursor_window_origin = test_api.GetCursorWindow()->bounds().origin();
230  EXPECT_EQ(30 - hot_point.x(), cursor_window_origin.x());
231  EXPECT_EQ(40 - hot_point.y(), cursor_window_origin.y());
232}
233
234// Make sure that the compositor based mirroring can switch
235// from/to dock mode.
236TEST_F(MirrorWindowControllerTest, MAYBE_DockMode) {
237  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
238  const int64 internal_id = 1;
239  const int64 external_id = 2;
240
241  const DisplayInfo internal_display_info =
242      CreateDisplayInfo(internal_id, gfx::Rect(0, 0, 500, 500));
243  const DisplayInfo external_display_info =
244      CreateDisplayInfo(external_id, gfx::Rect(1, 1, 100, 100));
245  std::vector<DisplayInfo> display_info_list;
246
247  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
248
249  // software mirroring.
250  display_info_list.push_back(internal_display_info);
251  display_info_list.push_back(external_display_info);
252  display_manager->OnNativeDisplaysChanged(display_info_list);
253  const int64 internal_display_id =
254      test::DisplayManagerTestApi(display_manager).
255      SetFirstDisplayAsInternalDisplay();
256  EXPECT_EQ(internal_id, internal_display_id);
257
258  EXPECT_EQ(1U, display_manager->GetNumDisplays());
259  EXPECT_TRUE(display_manager->IsMirrored());
260  EXPECT_EQ(external_id, display_manager->mirrored_display_id());
261
262  // dock mode.
263  display_info_list.clear();
264  display_info_list.push_back(external_display_info);
265  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
266  display_manager->OnNativeDisplaysChanged(display_info_list);
267  EXPECT_EQ(1U, display_manager->GetNumDisplays());
268  EXPECT_FALSE(display_manager->IsMirrored());
269
270  // back to software mirroring.
271  display_info_list.clear();
272  display_info_list.push_back(internal_display_info);
273  display_info_list.push_back(external_display_info);
274  display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
275  display_manager->OnNativeDisplaysChanged(display_info_list);
276  EXPECT_EQ(1U, display_manager->GetNumDisplays());
277  EXPECT_TRUE(display_manager->IsMirrored());
278  EXPECT_EQ(external_id, display_manager->mirrored_display_id());
279}
280
281TEST_F(MirrorOnBootTest, MAYBE_MirrorOnBoot) {
282  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
283  EXPECT_TRUE(display_manager->IsMirrored());
284  RunAllPendingInMessageLoop();
285  test::MirrorWindowTestApi test_api;
286  EXPECT_TRUE(test_api.GetHost());
287}
288
289}  // namespace ash
290