resolution_notification_controller_unittest.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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_util.h" 9#include "ash/shell.h" 10#include "ash/test/ash_test_base.h" 11#include "base/bind.h" 12#include "base/strings/utf_string_conversions.h" 13#include "grit/ash_strings.h" 14#include "ui/base/l10n/l10n_util.h" 15#include "ui/gfx/size.h" 16#include "ui/message_center/message_center.h" 17#include "ui/message_center/notification.h" 18#include "ui/message_center/notification_list.h" 19 20namespace ash { 21namespace { 22 23base::string16 ExpectedNotificationMessage(int64 display_id, 24 const gfx::Size& new_resolution) { 25 return l10n_util::GetStringFUTF16( 26 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, 27 base::UTF8ToUTF16( 28 Shell::GetInstance()->display_manager()->GetDisplayNameForId( 29 display_id)), 30 base::UTF8ToUTF16(new_resolution.ToString())); 31} 32 33base::string16 ExpectedFallbackNotificationMessage( 34 int64 display_id, 35 const gfx::Size& specified_resolution, 36 const gfx::Size& fallback_resolution) { 37 return l10n_util::GetStringFUTF16( 38 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED_TO_UNSUPPORTED, 39 base::UTF8ToUTF16( 40 Shell::GetInstance()->display_manager()->GetDisplayNameForId( 41 display_id)), 42 base::UTF8ToUTF16(specified_resolution.ToString()), 43 base::UTF8ToUTF16(fallback_resolution.ToString())); 44} 45 46} // namespace 47 48class ResolutionNotificationControllerTest : public ash::test::AshTestBase { 49 public: 50 ResolutionNotificationControllerTest() 51 : accept_count_(0) { 52 } 53 54 virtual ~ResolutionNotificationControllerTest() {} 55 56 protected: 57 virtual void SetUp() OVERRIDE { 58 ash::test::AshTestBase::SetUp(); 59 ResolutionNotificationController::SuppressTimerForTest(); 60 } 61 62 void SetDisplayResolutionAndNotifyWithResolution( 63 const gfx::Display& display, 64 const gfx::Size& new_resolution, 65 const gfx::Size& actual_new_resolution) { 66 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 67 const DisplayInfo& info = display_manager->GetDisplayInfo(display.id()); 68 controller()->SetDisplayResolutionAndNotify( 69 display.id(), 70 info.size_in_pixel(), 71 new_resolution, 72 base::Bind(&ResolutionNotificationControllerTest::OnAccepted, 73 base::Unretained(this))); 74 75 // OnConfigurationChanged event won't be emitted in the test environment, 76 // so invoke UpdateDisplay() to emit that event explicitly. 77 std::vector<DisplayInfo> info_list; 78 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 79 int64 id = display_manager->GetDisplayAt(i).id(); 80 DisplayInfo info = display_manager->GetDisplayInfo(id); 81 if (display.id() == id) { 82 gfx::Rect bounds = info.bounds_in_native(); 83 bounds.set_size(actual_new_resolution); 84 info.SetBounds(bounds); 85 } 86 info_list.push_back(info); 87 } 88 display_manager->OnNativeDisplaysChanged(info_list); 89 RunAllPendingInMessageLoop(); 90 } 91 92 void SetDisplayResolutionAndNotify(const gfx::Display& display, 93 const gfx::Size& new_resolution) { 94 SetDisplayResolutionAndNotifyWithResolution( 95 display, new_resolution, new_resolution); 96 } 97 98 static base::string16 GetNotificationMessage() { 99 const message_center::NotificationList::Notifications& notifications = 100 message_center::MessageCenter::Get()->GetVisibleNotifications(); 101 for (message_center::NotificationList::Notifications::const_iterator iter = 102 notifications.begin(); iter != notifications.end(); ++iter) { 103 if ((*iter)->id() == ResolutionNotificationController::kNotificationId) 104 return (*iter)->title(); 105 } 106 107 return base::string16(); 108 } 109 110 static void ClickOnNotification() { 111 message_center::MessageCenter::Get()->ClickOnNotification( 112 ResolutionNotificationController::kNotificationId); 113 } 114 115 static void ClickOnNotificationButton(int index) { 116 message_center::MessageCenter::Get()->ClickOnNotificationButton( 117 ResolutionNotificationController::kNotificationId, index); 118 } 119 120 static void CloseNotification() { 121 message_center::MessageCenter::Get()->RemoveNotification( 122 ResolutionNotificationController::kNotificationId, true /* by_user */); 123 } 124 125 static bool IsNotificationVisible() { 126 return message_center::MessageCenter::Get()->HasNotification( 127 ResolutionNotificationController::kNotificationId); 128 } 129 130 static void TickTimer() { 131 controller()->OnTimerTick(); 132 } 133 134 static ResolutionNotificationController* controller() { 135 return Shell::GetInstance()->resolution_notification_controller(); 136 } 137 138 int accept_count() const { 139 return accept_count_; 140 } 141 142 private: 143 void OnAccepted() { 144 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 145 accept_count_++; 146 } 147 148 int accept_count_; 149 150 DISALLOW_COPY_AND_ASSIGN(ResolutionNotificationControllerTest); 151}; 152 153// Basic behaviors and verifies it doesn't cause crashes. 154TEST_F(ResolutionNotificationControllerTest, Basic) { 155 if (!SupportsMultipleDisplays()) 156 return; 157 158 UpdateDisplay("300x300#300x300%57|200x200%58,250x250#250x250%59|200x200%60"); 159 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 160 ash::DisplayManager* display_manager = 161 ash::Shell::GetInstance()->display_manager(); 162 ASSERT_EQ(0, accept_count()); 163 EXPECT_FALSE(IsNotificationVisible()); 164 165 // Changes the resolution and apply the result. 166 SetDisplayResolutionAndNotify( 167 ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); 168 EXPECT_TRUE(IsNotificationVisible()); 169 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 170 EXPECT_EQ(ExpectedNotificationMessage(id2, gfx::Size(200, 200)), 171 GetNotificationMessage()); 172 DisplayMode mode; 173 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 174 EXPECT_EQ("200x200", mode.size.ToString()); 175 EXPECT_EQ(60.0, mode.refresh_rate); 176 177 // Click the revert button, which reverts to the best resolution. 178 ClickOnNotificationButton(0); 179 RunAllPendingInMessageLoop(); 180 EXPECT_FALSE(IsNotificationVisible()); 181 EXPECT_EQ(0, accept_count()); 182 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 183 EXPECT_EQ("250x250", mode.size.ToString()); 184 EXPECT_EQ(59.0, mode.refresh_rate); 185} 186 187TEST_F(ResolutionNotificationControllerTest, ClickMeansAccept) { 188 if (!SupportsMultipleDisplays()) 189 return; 190 191 UpdateDisplay("300x300#300x300%57|200x200%58,250x250#250x250%59|200x200%60"); 192 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 193 ash::DisplayManager* display_manager = 194 ash::Shell::GetInstance()->display_manager(); 195 ASSERT_EQ(0, accept_count()); 196 EXPECT_FALSE(IsNotificationVisible()); 197 198 // Changes the resolution and apply the result. 199 SetDisplayResolutionAndNotify( 200 ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); 201 EXPECT_TRUE(IsNotificationVisible()); 202 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 203 DisplayMode mode; 204 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 205 EXPECT_EQ("200x200", mode.size.ToString()); 206 EXPECT_EQ(60.0, mode.refresh_rate); 207 208 // Click the revert button, which reverts the resolution. 209 ClickOnNotification(); 210 RunAllPendingInMessageLoop(); 211 EXPECT_FALSE(IsNotificationVisible()); 212 EXPECT_EQ(1, accept_count()); 213 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 214 EXPECT_EQ("200x200", mode.size.ToString()); 215 EXPECT_EQ(60.0, mode.refresh_rate); 216} 217 218TEST_F(ResolutionNotificationControllerTest, AcceptButton) { 219 if (!SupportsMultipleDisplays()) 220 return; 221 222 ash::DisplayManager* display_manager = 223 ash::Shell::GetInstance()->display_manager(); 224 225 UpdateDisplay("300x300#300x300%59|200x200%60"); 226 const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay(); 227 SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); 228 EXPECT_TRUE(IsNotificationVisible()); 229 230 // If there's a single display only, it will have timeout and the first button 231 // becomes accept. 232 EXPECT_TRUE(controller()->DoesNotificationTimeout()); 233 ClickOnNotificationButton(0); 234 EXPECT_FALSE(IsNotificationVisible()); 235 EXPECT_EQ(1, accept_count()); 236 DisplayMode mode; 237 EXPECT_TRUE( 238 display_manager->GetSelectedModeForDisplayId(display.id(), &mode)); 239 EXPECT_EQ("200x200", mode.size.ToString()); 240 EXPECT_EQ(60.0f, mode.refresh_rate); 241 242 // In that case the second button is revert. 243 UpdateDisplay("300x300#300x300%59|200x200%60"); 244 SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); 245 EXPECT_TRUE(IsNotificationVisible()); 246 247 EXPECT_TRUE(controller()->DoesNotificationTimeout()); 248 ClickOnNotificationButton(1); 249 EXPECT_FALSE(IsNotificationVisible()); 250 EXPECT_EQ(1, accept_count()); 251 EXPECT_TRUE( 252 display_manager->GetSelectedModeForDisplayId(display.id(), &mode)); 253 EXPECT_EQ("300x300", mode.size.ToString()); 254 EXPECT_EQ(59.0f, mode.refresh_rate); 255} 256 257TEST_F(ResolutionNotificationControllerTest, Close) { 258 if (!SupportsMultipleDisplays()) 259 return; 260 261 UpdateDisplay("100x100,150x150#150x150%59|200x200%60"); 262 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 263 ash::DisplayManager* display_manager = 264 ash::Shell::GetInstance()->display_manager(); 265 ASSERT_EQ(0, accept_count()); 266 EXPECT_FALSE(IsNotificationVisible()); 267 268 // Changes the resolution and apply the result. 269 SetDisplayResolutionAndNotify( 270 ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); 271 EXPECT_TRUE(IsNotificationVisible()); 272 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 273 DisplayMode mode; 274 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 275 EXPECT_EQ("200x200", mode.size.ToString()); 276 EXPECT_EQ(60.0f, mode.refresh_rate); 277 278 // Close the notification (imitates clicking [x] button). Also verifies if 279 // this does not cause a crash. See crbug.com/271784 280 CloseNotification(); 281 RunAllPendingInMessageLoop(); 282 EXPECT_FALSE(IsNotificationVisible()); 283 EXPECT_EQ(1, accept_count()); 284} 285 286TEST_F(ResolutionNotificationControllerTest, Timeout) { 287 if (!SupportsMultipleDisplays()) 288 return; 289 290 UpdateDisplay("300x300#300x300%59|200x200%60"); 291 const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay(); 292 SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); 293 294 for (int i = 0; i < ResolutionNotificationController::kTimeoutInSec; ++i) { 295 EXPECT_TRUE(IsNotificationVisible()) << "notification is closed after " 296 << i << "-th timer tick"; 297 TickTimer(); 298 RunAllPendingInMessageLoop(); 299 } 300 EXPECT_FALSE(IsNotificationVisible()); 301 EXPECT_EQ(0, accept_count()); 302 ash::DisplayManager* display_manager = 303 ash::Shell::GetInstance()->display_manager(); 304 DisplayMode mode; 305 EXPECT_TRUE( 306 display_manager->GetSelectedModeForDisplayId(display.id(), &mode)); 307 EXPECT_EQ("300x300", mode.size.ToString()); 308 EXPECT_EQ(59.0f, mode.refresh_rate); 309} 310 311TEST_F(ResolutionNotificationControllerTest, DisplayDisconnected) { 312 if (!SupportsMultipleDisplays()) 313 return; 314 315 UpdateDisplay("300x300#300x300%56|200x200%57," 316 "200x200#250x250%58|200x200%59|100x100%60"); 317 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 318 ash::DisplayManager* display_manager = 319 ash::Shell::GetInstance()->display_manager(); 320 SetDisplayResolutionAndNotify( 321 ScreenUtil::GetSecondaryDisplay(), gfx::Size(100, 100)); 322 ASSERT_TRUE(IsNotificationVisible()); 323 324 // Disconnects the secondary display and verifies it doesn't cause crashes. 325 UpdateDisplay("300x300#300x300%56|200x200%57"); 326 RunAllPendingInMessageLoop(); 327 EXPECT_FALSE(IsNotificationVisible()); 328 EXPECT_EQ(0, accept_count()); 329 DisplayMode mode; 330 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 331 gfx::Size resolution; 332 EXPECT_EQ("200x200", mode.size.ToString()); 333 EXPECT_EQ(59.0f, mode.refresh_rate); 334} 335 336TEST_F(ResolutionNotificationControllerTest, MultipleResolutionChange) { 337 if (!SupportsMultipleDisplays()) 338 return; 339 340 UpdateDisplay("300x300#300x300%56|200x200%57," 341 "250x250#250x250%58|200x200%59"); 342 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 343 ash::DisplayManager* display_manager = 344 ash::Shell::GetInstance()->display_manager(); 345 346 SetDisplayResolutionAndNotify( 347 ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); 348 EXPECT_TRUE(IsNotificationVisible()); 349 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 350 DisplayMode mode; 351 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 352 EXPECT_EQ("200x200", mode.size.ToString()); 353 EXPECT_EQ(59.0f, mode.refresh_rate); 354 355 // Invokes SetDisplayResolutionAndNotify during the previous notification is 356 // visible. 357 SetDisplayResolutionAndNotify( 358 ScreenUtil::GetSecondaryDisplay(), gfx::Size(250, 250)); 359 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 360 EXPECT_EQ("250x250", mode.size.ToString()); 361 EXPECT_EQ(58.0f, mode.refresh_rate); 362 363 // Then, click the revert button. Although |old_resolution| for the second 364 // SetDisplayResolutionAndNotify is 200x200, it should revert to the original 365 // size 250x250. 366 ClickOnNotificationButton(0); 367 RunAllPendingInMessageLoop(); 368 EXPECT_FALSE(IsNotificationVisible()); 369 EXPECT_EQ(0, accept_count()); 370 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 371 EXPECT_EQ("250x250", mode.size.ToString()); 372 EXPECT_EQ(58.0f, mode.refresh_rate); 373} 374 375TEST_F(ResolutionNotificationControllerTest, Fallback) { 376 if (!SupportsMultipleDisplays()) 377 return; 378 379 UpdateDisplay("300x300#300x300%56|200x200%57," 380 "250x250#250x250%58|220x220%59|200x200%60"); 381 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 382 ash::DisplayManager* display_manager = 383 ash::Shell::GetInstance()->display_manager(); 384 ASSERT_EQ(0, accept_count()); 385 EXPECT_FALSE(IsNotificationVisible()); 386 387 // Changes the resolution and apply the result. 388 SetDisplayResolutionAndNotifyWithResolution( 389 ScreenUtil::GetSecondaryDisplay(), 390 gfx::Size(220, 220), 391 gfx::Size(200, 200)); 392 EXPECT_TRUE(IsNotificationVisible()); 393 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 394 EXPECT_EQ( 395 ExpectedFallbackNotificationMessage( 396 id2, gfx::Size(220, 220), gfx::Size(200, 200)), 397 GetNotificationMessage()); 398 DisplayMode mode; 399 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 400 EXPECT_EQ("200x200", mode.size.ToString()); 401 EXPECT_EQ(60.0f, mode.refresh_rate); 402 403 // Click the revert button, which reverts to the best resolution. 404 ClickOnNotificationButton(0); 405 RunAllPendingInMessageLoop(); 406 EXPECT_FALSE(IsNotificationVisible()); 407 EXPECT_EQ(0, accept_count()); 408 EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); 409 EXPECT_EQ("250x250", mode.size.ToString()); 410 EXPECT_EQ(58.0f, mode.refresh_rate); 411} 412 413} // namespace ash 414