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 15 namespace ash { 16 namespace internal { 17 18 class 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::string display_spec; 47 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { 48 if (i > 0) 49 display_spec.append(","); 50 int64 id = display_manager->GetDisplayAt(i).id(); 51 gfx::Size size = (display.id() == id) ? 52 new_resolution : display_manager->GetDisplayInfo(id).size_in_pixel(); 53 display_spec.append(size.ToString()); 54 } 55 UpdateDisplay(display_spec); 56 RunAllPendingInMessageLoop(); 57 } 58 59 void ClickOnNotification() { 60 message_center::MessageCenter::Get()->ClickOnNotification( 61 ResolutionNotificationController::kNotificationId); 62 } 63 64 void ClickOnNotificationButton(int index) { 65 message_center::MessageCenter::Get()->ClickOnNotificationButton( 66 ResolutionNotificationController::kNotificationId, index); 67 } 68 69 void CloseNotification() { 70 message_center::MessageCenter::Get()->RemoveNotification( 71 ResolutionNotificationController::kNotificationId, true /* by_user */); 72 } 73 74 bool IsNotificationVisible() { 75 return message_center::MessageCenter::Get()->HasNotification( 76 ResolutionNotificationController::kNotificationId); 77 } 78 79 void TickTimer() { 80 controller()->OnTimerTick(); 81 } 82 83 ResolutionNotificationController* controller() { 84 return Shell::GetInstance()->resolution_notification_controller(); 85 } 86 87 int accept_count() const { 88 return accept_count_; 89 } 90 91 private: 92 void OnAccepted() { 93 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 94 accept_count_++; 95 } 96 97 int accept_count_; 98 99 DISALLOW_COPY_AND_ASSIGN(ResolutionNotificationControllerTest); 100 }; 101 102 // Basic behaviors and verifies it doesn't cause crashes. 103 TEST_F(ResolutionNotificationControllerTest, Basic) { 104 if (!SupportsMultipleDisplays()) 105 return; 106 107 UpdateDisplay("100x100,150x150"); 108 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 109 ash::internal::DisplayManager* display_manager = 110 ash::Shell::GetInstance()->display_manager(); 111 ASSERT_EQ(0, accept_count()); 112 EXPECT_FALSE(IsNotificationVisible()); 113 114 // Changes the resolution and apply the result. 115 SetDisplayResolutionAndNotify( 116 ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200)); 117 EXPECT_TRUE(IsNotificationVisible()); 118 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 119 gfx::Size resolution; 120 EXPECT_TRUE( 121 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 122 EXPECT_EQ("200x200", resolution.ToString()); 123 124 // Click the revert button, which reverts the resolution. 125 ClickOnNotificationButton(0); 126 RunAllPendingInMessageLoop(); 127 EXPECT_FALSE(IsNotificationVisible()); 128 EXPECT_EQ(0, accept_count()); 129 EXPECT_TRUE( 130 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 131 EXPECT_EQ("150x150", resolution.ToString()); 132 } 133 134 TEST_F(ResolutionNotificationControllerTest, ClickMeansAccept) { 135 if (!SupportsMultipleDisplays()) 136 return; 137 138 UpdateDisplay("100x100,150x150"); 139 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 140 ash::internal::DisplayManager* display_manager = 141 ash::Shell::GetInstance()->display_manager(); 142 ASSERT_EQ(0, accept_count()); 143 EXPECT_FALSE(IsNotificationVisible()); 144 145 // Changes the resolution and apply the result. 146 SetDisplayResolutionAndNotify( 147 ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200)); 148 EXPECT_TRUE(IsNotificationVisible()); 149 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 150 gfx::Size resolution; 151 EXPECT_TRUE( 152 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 153 EXPECT_EQ("200x200", resolution.ToString()); 154 155 // Click the revert button, which reverts the resolution. 156 ClickOnNotification(); 157 RunAllPendingInMessageLoop(); 158 EXPECT_FALSE(IsNotificationVisible()); 159 EXPECT_EQ(1, accept_count()); 160 EXPECT_TRUE( 161 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 162 EXPECT_EQ("200x200", resolution.ToString()); 163 } 164 165 TEST_F(ResolutionNotificationControllerTest, AcceptButton) { 166 if (!SupportsMultipleDisplays()) 167 return; 168 169 ash::internal::DisplayManager* display_manager = 170 ash::Shell::GetInstance()->display_manager(); 171 172 UpdateDisplay("100x100"); 173 const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay(); 174 SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); 175 EXPECT_TRUE(IsNotificationVisible()); 176 177 // If there's a single display only, it will have timeout and the first button 178 // becomes accept. 179 EXPECT_TRUE(controller()->DoesNotificationTimeout()); 180 ClickOnNotificationButton(0); 181 EXPECT_FALSE(IsNotificationVisible()); 182 EXPECT_EQ(1, accept_count()); 183 gfx::Size resolution; 184 EXPECT_TRUE(display_manager->GetSelectedResolutionForDisplayId( 185 display.id(), &resolution)); 186 EXPECT_EQ("200x200", resolution.ToString()); 187 188 // In that case the second button is revert. 189 UpdateDisplay("100x100"); 190 SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); 191 EXPECT_TRUE(IsNotificationVisible()); 192 193 EXPECT_TRUE(controller()->DoesNotificationTimeout()); 194 ClickOnNotificationButton(1); 195 EXPECT_FALSE(IsNotificationVisible()); 196 EXPECT_EQ(1, accept_count()); 197 EXPECT_TRUE(display_manager->GetSelectedResolutionForDisplayId( 198 display.id(), &resolution)); 199 EXPECT_EQ("100x100", resolution.ToString()); 200 } 201 202 TEST_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 231 TEST_F(ResolutionNotificationControllerTest, Timeout) { 232 if (!SupportsMultipleDisplays()) 233 return; 234 235 UpdateDisplay("100x100"); 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_TRUE(display_manager->GetSelectedResolutionForDisplayId( 251 display.id(), &resolution)); 252 EXPECT_EQ("100x100", resolution.ToString()); 253 } 254 255 TEST_F(ResolutionNotificationControllerTest, DisplayDisconnected) { 256 if (!SupportsMultipleDisplays()) 257 return; 258 259 UpdateDisplay("100x100,150x150"); 260 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 261 ash::internal::DisplayManager* display_manager = 262 ash::Shell::GetInstance()->display_manager(); 263 SetDisplayResolutionAndNotify( 264 ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200)); 265 ASSERT_TRUE(IsNotificationVisible()); 266 267 // Disconnects the secondary display and verifies it doesn't cause crashes. 268 UpdateDisplay("100x100"); 269 RunAllPendingInMessageLoop(); 270 EXPECT_FALSE(IsNotificationVisible()); 271 EXPECT_EQ(0, accept_count()); 272 gfx::Size resolution; 273 EXPECT_TRUE( 274 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 275 EXPECT_EQ("150x150", resolution.ToString()); 276 } 277 278 TEST_F(ResolutionNotificationControllerTest, MultipleResolutionChange) { 279 if (!SupportsMultipleDisplays()) 280 return; 281 282 UpdateDisplay("100x100,150x150"); 283 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 284 ash::internal::DisplayManager* display_manager = 285 ash::Shell::GetInstance()->display_manager(); 286 287 SetDisplayResolutionAndNotify( 288 ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200)); 289 EXPECT_TRUE(IsNotificationVisible()); 290 EXPECT_FALSE(controller()->DoesNotificationTimeout()); 291 gfx::Size resolution; 292 EXPECT_TRUE( 293 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 294 EXPECT_EQ("200x200", resolution.ToString()); 295 296 // Invokes SetDisplayResolutionAndNotify during the previous notification is 297 // visible. 298 SetDisplayResolutionAndNotify( 299 ScreenAsh::GetSecondaryDisplay(), gfx::Size(250, 250)); 300 EXPECT_TRUE( 301 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 302 EXPECT_EQ("250x250", resolution.ToString()); 303 304 // Then, click the revert button. Although |old_resolution| for the second 305 // SetDisplayResolutionAndNotify is 200x200, it should revert to the original 306 // size 150x150. 307 ClickOnNotificationButton(0); 308 RunAllPendingInMessageLoop(); 309 EXPECT_FALSE(IsNotificationVisible()); 310 EXPECT_EQ(0, accept_count()); 311 EXPECT_TRUE( 312 display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); 313 EXPECT_EQ("150x150", resolution.ToString()); 314 } 315 316 } // namespace internal 317 } // namespace ash 318