resolution_notification_controller_unittest.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
1// Copyright 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/resolution_notification_controller.h"
6
7#include "ash/display/display_manager.h"
8#include "ash/screen_ash.h"
9#include "ash/shell.h"
10#include "ash/test/ash_test_base.h"
11#include "base/bind.h"
12#include "ui/gfx/size.h"
13#include "ui/message_center/message_center.h"
14
15namespace ash {
16namespace internal {
17
18class ResolutionNotificationControllerTest : public ash::test::AshTestBase {
19 public:
20  ResolutionNotificationControllerTest()
21      : accept_count_(0) {
22  }
23
24  virtual ~ResolutionNotificationControllerTest() {}
25
26 protected:
27  virtual void SetUp() OVERRIDE {
28    ash::test::AshTestBase::SetUp();
29    ResolutionNotificationController::SuppressTimerForTest();
30  }
31
32  void SetDisplayResolutionAndNotify(const gfx::Display& display,
33                                     const gfx::Size& new_resolution) {
34    DisplayManager* display_manager = Shell::GetInstance()->display_manager();
35    const DisplayInfo& info = display_manager->GetDisplayInfo(display.id());
36    Shell::GetInstance()->resolution_notification_controller()->
37        SetDisplayResolutionAndNotify(
38            display.id(),
39            info.size_in_pixel(),
40            new_resolution,
41            base::Bind(&ResolutionNotificationControllerTest::OnAccepted,
42                       base::Unretained(this)));
43
44    // OnConfigurationChanged event won't be emitted in the test environment,
45    // so invoke UpdateDisplay() to emit that event explicitly.
46    std::vector<DisplayInfo> info_list;
47    for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
48      int64 id = display_manager->GetDisplayAt(i).id();
49      DisplayInfo info = display_manager->GetDisplayInfo(id);
50      if (display.id() == id) {
51        gfx::Rect bounds = info.bounds_in_native();
52        bounds.set_size(new_resolution);
53        info.SetBounds(bounds);
54      }
55      info_list.push_back(info);
56    }
57    display_manager->OnNativeDisplaysChanged(info_list);
58    RunAllPendingInMessageLoop();
59  }
60
61  void ClickOnNotification() {
62    message_center::MessageCenter::Get()->ClickOnNotification(
63        ResolutionNotificationController::kNotificationId);
64  }
65
66  void ClickOnNotificationButton(int index) {
67    message_center::MessageCenter::Get()->ClickOnNotificationButton(
68        ResolutionNotificationController::kNotificationId, index);
69  }
70
71  void CloseNotification() {
72    message_center::MessageCenter::Get()->RemoveNotification(
73        ResolutionNotificationController::kNotificationId, true /* by_user */);
74  }
75
76  bool IsNotificationVisible() {
77    return message_center::MessageCenter::Get()->HasNotification(
78        ResolutionNotificationController::kNotificationId);
79  }
80
81  void TickTimer() {
82    controller()->OnTimerTick();
83  }
84
85  ResolutionNotificationController* controller() {
86    return Shell::GetInstance()->resolution_notification_controller();
87  }
88
89  int accept_count() const {
90    return accept_count_;
91  }
92
93 private:
94  void OnAccepted() {
95    EXPECT_FALSE(controller()->DoesNotificationTimeout());
96    accept_count_++;
97  }
98
99  int accept_count_;
100
101  DISALLOW_COPY_AND_ASSIGN(ResolutionNotificationControllerTest);
102};
103
104// Basic behaviors and verifies it doesn't cause crashes.
105TEST_F(ResolutionNotificationControllerTest, Basic) {
106  if (!SupportsMultipleDisplays())
107    return;
108
109  UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200");
110  int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
111  ash::internal::DisplayManager* display_manager =
112      ash::Shell::GetInstance()->display_manager();
113  ASSERT_EQ(0, accept_count());
114  EXPECT_FALSE(IsNotificationVisible());
115
116  // Changes the resolution and apply the result.
117  SetDisplayResolutionAndNotify(
118      ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200));
119  EXPECT_TRUE(IsNotificationVisible());
120  EXPECT_FALSE(controller()->DoesNotificationTimeout());
121  gfx::Size resolution;
122  EXPECT_TRUE(
123      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
124  EXPECT_EQ("200x200", resolution.ToString());
125
126  // Click the revert button, which reverts to the best resolution.
127  ClickOnNotificationButton(0);
128  RunAllPendingInMessageLoop();
129  EXPECT_FALSE(IsNotificationVisible());
130  EXPECT_EQ(0, accept_count());
131  EXPECT_FALSE(
132      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
133}
134
135TEST_F(ResolutionNotificationControllerTest, ClickMeansAccept) {
136  if (!SupportsMultipleDisplays())
137    return;
138
139  UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200");
140  int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
141  ash::internal::DisplayManager* display_manager =
142      ash::Shell::GetInstance()->display_manager();
143  ASSERT_EQ(0, accept_count());
144  EXPECT_FALSE(IsNotificationVisible());
145
146  // Changes the resolution and apply the result.
147  SetDisplayResolutionAndNotify(
148      ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200));
149  EXPECT_TRUE(IsNotificationVisible());
150  EXPECT_FALSE(controller()->DoesNotificationTimeout());
151  gfx::Size resolution;
152  EXPECT_TRUE(
153      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
154  EXPECT_EQ("200x200", resolution.ToString());
155
156  // Click the revert button, which reverts the resolution.
157  ClickOnNotification();
158  RunAllPendingInMessageLoop();
159  EXPECT_FALSE(IsNotificationVisible());
160  EXPECT_EQ(1, accept_count());
161  EXPECT_TRUE(
162      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
163  EXPECT_EQ("200x200", resolution.ToString());
164}
165
166TEST_F(ResolutionNotificationControllerTest, AcceptButton) {
167  if (!SupportsMultipleDisplays())
168    return;
169
170  ash::internal::DisplayManager* display_manager =
171      ash::Shell::GetInstance()->display_manager();
172
173  UpdateDisplay("300x300#300x300|200x200");
174  const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay();
175  SetDisplayResolutionAndNotify(display, gfx::Size(200, 200));
176  EXPECT_TRUE(IsNotificationVisible());
177
178  // If there's a single display only, it will have timeout and the first button
179  // becomes accept.
180  EXPECT_TRUE(controller()->DoesNotificationTimeout());
181  ClickOnNotificationButton(0);
182  EXPECT_FALSE(IsNotificationVisible());
183  EXPECT_EQ(1, accept_count());
184  gfx::Size resolution;
185  EXPECT_TRUE(display_manager->GetSelectedResolutionForDisplayId(
186      display.id(), &resolution));
187  EXPECT_EQ("200x200", resolution.ToString());
188
189  // In that case the second button is revert.
190  UpdateDisplay("300x300#300x300|200x200");
191  SetDisplayResolutionAndNotify(display, gfx::Size(200, 200));
192  EXPECT_TRUE(IsNotificationVisible());
193
194  EXPECT_TRUE(controller()->DoesNotificationTimeout());
195  ClickOnNotificationButton(1);
196  EXPECT_FALSE(IsNotificationVisible());
197  EXPECT_EQ(1, accept_count());
198  EXPECT_FALSE(display_manager->GetSelectedResolutionForDisplayId(
199      display.id(), &resolution));
200}
201
202TEST_F(ResolutionNotificationControllerTest, Close) {
203  if (!SupportsMultipleDisplays())
204    return;
205
206  UpdateDisplay("100x100,150x150#150x150|200x200");
207  int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
208  ash::internal::DisplayManager* display_manager =
209      ash::Shell::GetInstance()->display_manager();
210  ASSERT_EQ(0, accept_count());
211  EXPECT_FALSE(IsNotificationVisible());
212
213  // Changes the resolution and apply the result.
214  SetDisplayResolutionAndNotify(
215      ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200));
216  EXPECT_TRUE(IsNotificationVisible());
217  EXPECT_FALSE(controller()->DoesNotificationTimeout());
218  gfx::Size resolution;
219  EXPECT_TRUE(
220      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
221  EXPECT_EQ("200x200", resolution.ToString());
222
223  // Close the notification (imitates clicking [x] button). Also verifies if
224  // this does not cause a crash.  See crbug.com/271784
225  CloseNotification();
226  RunAllPendingInMessageLoop();
227  EXPECT_FALSE(IsNotificationVisible());
228  EXPECT_EQ(1, accept_count());
229}
230
231TEST_F(ResolutionNotificationControllerTest, Timeout) {
232  if (!SupportsMultipleDisplays())
233    return;
234
235  UpdateDisplay("300x300#300x300|200x200");
236  const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay();
237  SetDisplayResolutionAndNotify(display, gfx::Size(200, 200));
238
239  for (int i = 0; i < ResolutionNotificationController::kTimeoutInSec; ++i) {
240    EXPECT_TRUE(IsNotificationVisible()) << "notification is closed after "
241                                         << i << "-th timer tick";
242    TickTimer();
243    RunAllPendingInMessageLoop();
244  }
245  EXPECT_FALSE(IsNotificationVisible());
246  EXPECT_EQ(0, accept_count());
247  gfx::Size resolution;
248  ash::internal::DisplayManager* display_manager =
249      ash::Shell::GetInstance()->display_manager();
250  EXPECT_FALSE(display_manager->GetSelectedResolutionForDisplayId(
251      display.id(), &resolution));
252}
253
254TEST_F(ResolutionNotificationControllerTest, DisplayDisconnected) {
255  if (!SupportsMultipleDisplays())
256    return;
257
258  UpdateDisplay("300x300#300x300|200x200,200x200#250x250|200x200|100x100");
259  int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
260  ash::internal::DisplayManager* display_manager =
261      ash::Shell::GetInstance()->display_manager();
262  SetDisplayResolutionAndNotify(
263      ScreenAsh::GetSecondaryDisplay(), gfx::Size(100, 100));
264  ASSERT_TRUE(IsNotificationVisible());
265
266  // Disconnects the secondary display and verifies it doesn't cause crashes.
267  UpdateDisplay("300x300#300x300|200x200");
268  RunAllPendingInMessageLoop();
269  EXPECT_FALSE(IsNotificationVisible());
270  EXPECT_EQ(0, accept_count());
271  gfx::Size resolution;
272  EXPECT_TRUE(
273      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
274  EXPECT_EQ("200x200", resolution.ToString());
275}
276
277TEST_F(ResolutionNotificationControllerTest, MultipleResolutionChange) {
278  if (!SupportsMultipleDisplays())
279    return;
280
281  UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200");
282  int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
283  ash::internal::DisplayManager* display_manager =
284      ash::Shell::GetInstance()->display_manager();
285
286  SetDisplayResolutionAndNotify(
287      ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200));
288  EXPECT_TRUE(IsNotificationVisible());
289  EXPECT_FALSE(controller()->DoesNotificationTimeout());
290  gfx::Size resolution;
291  EXPECT_TRUE(
292      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
293  EXPECT_EQ("200x200", resolution.ToString());
294
295  // Invokes SetDisplayResolutionAndNotify during the previous notification is
296  // visible.
297  SetDisplayResolutionAndNotify(
298      ScreenAsh::GetSecondaryDisplay(), gfx::Size(250, 250));
299  EXPECT_FALSE(
300      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
301
302  // Then, click the revert button. Although |old_resolution| for the second
303  // SetDisplayResolutionAndNotify is 200x200, it should revert to the original
304  // size 150x150.
305  ClickOnNotificationButton(0);
306  RunAllPendingInMessageLoop();
307  EXPECT_FALSE(IsNotificationVisible());
308  EXPECT_EQ(0, accept_count());
309  EXPECT_FALSE(
310      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
311}
312
313}  // namespace internal
314}  // namespace ash
315