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/system/chromeos/tray_display.h" 6 7 #include "ash/display/display_manager.h" 8 #include "ash/root_window_controller.h" 9 #include "ash/screen_ash.h" 10 #include "ash/shell.h" 11 #include "ash/system/tray/system_tray.h" 12 #include "ash/system/tray/test_system_tray_delegate.h" 13 #include "ash/test/ash_test_base.h" 14 #include "base/strings/string16.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "grit/ash_strings.h" 17 #include "ui/base/l10n/l10n_util.h" 18 #include "ui/gfx/display.h" 19 #include "ui/views/controls/label.h" 20 21 namespace ash { 22 namespace internal { 23 24 base::string16 GetTooltipText(const base::string16& headline, 25 const base::string16& name1, 26 const std::string& data1, 27 const base::string16& name2, 28 const std::string& data2) { 29 std::vector<base::string16> lines; 30 lines.push_back(headline); 31 lines.push_back(l10n_util::GetStringFUTF16( 32 IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY, 33 name1, UTF8ToUTF16(data1))); 34 if (!name2.empty()) { 35 lines.push_back(l10n_util::GetStringFUTF16( 36 IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY, 37 name2, UTF8ToUTF16(data2))); 38 } 39 return JoinString(lines, '\n'); 40 } 41 42 base::string16 GetMirroredTooltipText(const base::string16& headline, 43 const base::string16& name, 44 const std::string& data) { 45 return GetTooltipText(headline, name, data, base::string16(), ""); 46 } 47 48 base::string16 GetFirstDisplayName() { 49 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 50 return UTF8ToUTF16(display_manager->GetDisplayNameForId( 51 display_manager->first_display_id())); 52 } 53 54 base::string16 GetSecondDisplayName() { 55 return UTF8ToUTF16( 56 Shell::GetInstance()->display_manager()->GetDisplayNameForId( 57 ScreenAsh::GetSecondaryDisplay().id())); 58 } 59 60 base::string16 GetMirroredDisplayName() { 61 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 62 return UTF8ToUTF16(display_manager->GetDisplayNameForId( 63 display_manager->mirrored_display().id())); 64 } 65 66 class TrayDisplayTest : public ash::test::AshTestBase { 67 public: 68 TrayDisplayTest(); 69 virtual ~TrayDisplayTest(); 70 71 virtual void SetUp() OVERRIDE; 72 73 protected: 74 SystemTray* tray() { return tray_; } 75 TrayDisplay* tray_display() { return tray_display_; } 76 77 void CloseNotification(); 78 bool IsDisplayVisibleInTray(); 79 base::string16 GetTrayDisplayText(); 80 base::string16 GetTrayDisplayTooltipText(); 81 base::string16 GetDisplayNotificationText(); 82 83 private: 84 // Weak reference, owned by Shell. 85 SystemTray* tray_; 86 87 // Weak reference, owned by |tray_|. 88 TrayDisplay* tray_display_; 89 90 DISALLOW_COPY_AND_ASSIGN(TrayDisplayTest); 91 }; 92 93 TrayDisplayTest::TrayDisplayTest() : tray_(NULL), tray_display_(NULL) { 94 } 95 96 TrayDisplayTest::~TrayDisplayTest() { 97 } 98 99 void TrayDisplayTest::SetUp() { 100 ash::test::AshTestBase::SetUp(); 101 tray_ = Shell::GetPrimaryRootWindowController()->GetSystemTray(); 102 tray_display_ = new TrayDisplay(tray_); 103 tray_->AddTrayItem(tray_display_); 104 } 105 106 void TrayDisplayTest::CloseNotification() { 107 tray_display_->CloseNotificationForTest(); 108 RunAllPendingInMessageLoop(); 109 } 110 111 bool TrayDisplayTest::IsDisplayVisibleInTray() { 112 return tray_display_->default_view() && 113 tray_display_->default_view()->visible(); 114 } 115 116 base::string16 TrayDisplayTest::GetTrayDisplayText() { 117 return tray_display_->GetDefaultViewMessage(); 118 } 119 120 base::string16 TrayDisplayTest::GetTrayDisplayTooltipText() { 121 if (!tray_display_->default_view()) 122 return base::string16(); 123 124 base::string16 tooltip; 125 if (!tray_display_->default_view()->GetTooltipText(gfx::Point(), &tooltip)) 126 return base::string16(); 127 return tooltip; 128 } 129 130 base::string16 TrayDisplayTest::GetDisplayNotificationText() { 131 return tray_display_->GetNotificationMessage(); 132 } 133 134 TEST_F(TrayDisplayTest, NoInternalDisplay) { 135 UpdateDisplay("400x400"); 136 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 137 EXPECT_FALSE(IsDisplayVisibleInTray()); 138 139 UpdateDisplay("400x400,200x200"); 140 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 141 EXPECT_TRUE(IsDisplayVisibleInTray()); 142 base::string16 expected = l10n_util::GetStringUTF16( 143 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL); 144 base::string16 first_name = GetFirstDisplayName(); 145 EXPECT_EQ(expected, GetTrayDisplayText()); 146 EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400", 147 GetSecondDisplayName(), "200x200"), 148 GetTrayDisplayTooltipText()); 149 150 // mirroring 151 Shell::GetInstance()->display_manager()->SetSoftwareMirroring(true); 152 UpdateDisplay("400x400,200x200"); 153 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 154 EXPECT_TRUE(IsDisplayVisibleInTray()); 155 expected = l10n_util::GetStringUTF16( 156 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL); 157 EXPECT_EQ(expected, GetTrayDisplayText()); 158 EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"), 159 GetTrayDisplayTooltipText()); 160 } 161 162 TEST_F(TrayDisplayTest, InternalDisplay) { 163 UpdateDisplay("400x400"); 164 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 165 gfx::Display::SetInternalDisplayId(display_manager->first_display_id()); 166 167 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 168 EXPECT_FALSE(IsDisplayVisibleInTray()); 169 170 // Extended 171 UpdateDisplay("400x400,200x200"); 172 string16 expected = l10n_util::GetStringFUTF16( 173 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()); 174 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 175 EXPECT_TRUE(IsDisplayVisibleInTray()); 176 EXPECT_EQ(expected, GetTrayDisplayText()); 177 EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400", 178 GetSecondDisplayName(), "200x200"), 179 GetTrayDisplayTooltipText()); 180 181 // Mirroring 182 display_manager->SetSoftwareMirroring(true); 183 UpdateDisplay("400x400,200x200"); 184 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 185 EXPECT_TRUE(IsDisplayVisibleInTray()); 186 187 expected = l10n_util::GetStringFUTF16( 188 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName()); 189 EXPECT_EQ(expected, GetTrayDisplayText()); 190 EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"), 191 GetTrayDisplayTooltipText()); 192 193 // TODO(mukai): add test case for docked mode here. 194 } 195 196 TEST_F(TrayDisplayTest, InternalDisplayResized) { 197 UpdateDisplay("400x400 (at) 1.5"); 198 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 199 gfx::Display::SetInternalDisplayId(display_manager->first_display_id()); 200 201 // Shows the tray_display even though there's a single-display. 202 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 203 EXPECT_TRUE(IsDisplayVisibleInTray()); 204 base::string16 internal_info = l10n_util::GetStringFUTF16( 205 IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY, 206 GetFirstDisplayName(), UTF8ToUTF16("600x600")); 207 EXPECT_EQ(internal_info, GetTrayDisplayText()); 208 EXPECT_EQ(GetTooltipText(base::string16(), GetFirstDisplayName(), "600x600", 209 base::string16(), std::string()), 210 GetTrayDisplayTooltipText()); 211 212 // Extended 213 UpdateDisplay("400x400 (at) 1.5,200x200"); 214 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 215 EXPECT_TRUE(IsDisplayVisibleInTray()); 216 base::string16 expected = l10n_util::GetStringFUTF16( 217 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()); 218 EXPECT_EQ(expected, GetTrayDisplayText()); 219 EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "600x600", 220 GetSecondDisplayName(), "200x200"), 221 GetTrayDisplayTooltipText()); 222 223 // Mirroring 224 display_manager->SetSoftwareMirroring(true); 225 UpdateDisplay("400x400 (at) 1.5,200x200"); 226 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 227 EXPECT_TRUE(IsDisplayVisibleInTray()); 228 expected = l10n_util::GetStringFUTF16( 229 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName()); 230 EXPECT_EQ(expected, GetTrayDisplayText()); 231 EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "600x600"), 232 GetTrayDisplayTooltipText()); 233 } 234 235 TEST_F(TrayDisplayTest, ExternalDisplayResized) { 236 UpdateDisplay("400x400"); 237 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 238 gfx::Display::SetInternalDisplayId(display_manager->first_display_id()); 239 240 // Shows the tray_display even though there's a single-display. 241 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 242 EXPECT_FALSE(IsDisplayVisibleInTray()); 243 244 // Extended 245 UpdateDisplay("400x400,200x200 (at) 1.5"); 246 const gfx::Display& secondary_display = ScreenAsh::GetSecondaryDisplay(); 247 248 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 249 EXPECT_TRUE(IsDisplayVisibleInTray()); 250 base::string16 expected = l10n_util::GetStringFUTF16( 251 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, 252 l10n_util::GetStringFUTF16( 253 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, 254 GetSecondDisplayName(), 255 UTF8ToUTF16(secondary_display.size().ToString()))); 256 EXPECT_EQ(expected, GetTrayDisplayText()); 257 EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400", 258 GetSecondDisplayName(), "300x300"), 259 GetTrayDisplayTooltipText()); 260 261 // Mirroring 262 display_manager->SetSoftwareMirroring(true); 263 UpdateDisplay("400x400,200x200 (at) 1.5"); 264 base::string16 mirror_name = l10n_util::GetStringFUTF16( 265 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, 266 GetMirroredDisplayName(), UTF8ToUTF16("300x300")); 267 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 268 EXPECT_TRUE(IsDisplayVisibleInTray()); 269 expected = l10n_util::GetStringFUTF16( 270 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, mirror_name); 271 EXPECT_EQ(expected, GetTrayDisplayText()); 272 EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"), 273 GetTrayDisplayTooltipText()); 274 } 275 276 TEST_F(TrayDisplayTest, OverscanDisplay) { 277 UpdateDisplay("400x400,300x300/o"); 278 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 279 gfx::Display::SetInternalDisplayId(display_manager->first_display_id()); 280 281 tray()->ShowDefaultView(BUBBLE_USE_EXISTING); 282 EXPECT_TRUE(IsDisplayVisibleInTray()); 283 284 // /o creates the default overscan, and if overscan is set, the annotation 285 // should be the size. 286 base::string16 overscan = l10n_util::GetStringUTF16( 287 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN); 288 base::string16 headline = l10n_util::GetStringFUTF16( 289 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, 290 l10n_util::GetStringFUTF16( 291 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, 292 GetSecondDisplayName(), UTF8ToUTF16("286x286"))); 293 std::string second_data = l10n_util::GetStringFUTF8( 294 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION, 295 UTF8ToUTF16("286x286"), overscan); 296 EXPECT_EQ(GetTooltipText(headline, GetFirstDisplayName(), "400x400", 297 GetSecondDisplayName(), second_data), 298 GetTrayDisplayTooltipText()); 299 300 // reset the overscan. 301 display_manager->SetOverscanInsets( 302 ScreenAsh::GetSecondaryDisplay().id(), gfx::Insets()); 303 headline = l10n_util::GetStringFUTF16( 304 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, 305 l10n_util::GetStringFUTF16( 306 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, 307 GetSecondDisplayName(), overscan)); 308 second_data = l10n_util::GetStringFUTF8( 309 IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION, 310 UTF8ToUTF16("300x300"), overscan); 311 EXPECT_EQ(GetTooltipText(headline, GetFirstDisplayName(), "400x400", 312 GetSecondDisplayName(), second_data), 313 GetTrayDisplayTooltipText()); 314 } 315 316 TEST_F(TrayDisplayTest, DisplayNotifications) { 317 test::TestSystemTrayDelegate* tray_delegate = 318 static_cast<test::TestSystemTrayDelegate*>( 319 Shell::GetInstance()->system_tray_delegate()); 320 tray_delegate->set_should_show_display_notification(true); 321 322 UpdateDisplay("400x400"); 323 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 324 gfx::Display::SetInternalDisplayId(display_manager->first_display_id()); 325 EXPECT_TRUE(GetDisplayNotificationText().empty()); 326 327 // rotation. 328 UpdateDisplay("400x400/r"); 329 EXPECT_EQ( 330 l10n_util::GetStringFUTF16( 331 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(), 332 l10n_util::GetStringUTF16( 333 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), 334 GetDisplayNotificationText()); 335 336 CloseNotification(); 337 UpdateDisplay("400x400"); 338 EXPECT_EQ( 339 l10n_util::GetStringFUTF16( 340 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(), 341 l10n_util::GetStringUTF16( 342 IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION)), 343 GetDisplayNotificationText()); 344 345 // UI-scale 346 CloseNotification(); 347 UpdateDisplay("400x400 (at) 1.5"); 348 EXPECT_EQ( 349 l10n_util::GetStringFUTF16( 350 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, 351 GetFirstDisplayName(), UTF8ToUTF16("600x600")), 352 GetDisplayNotificationText()); 353 354 // UI-scale to 1.0 355 CloseNotification(); 356 UpdateDisplay("400x400"); 357 EXPECT_EQ( 358 l10n_util::GetStringFUTF16( 359 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, 360 GetFirstDisplayName(), UTF8ToUTF16("400x400")), 361 GetDisplayNotificationText()); 362 363 // No-update 364 CloseNotification(); 365 UpdateDisplay("400x400"); 366 EXPECT_TRUE(GetDisplayNotificationText().empty()); 367 368 // Extended. 369 CloseNotification(); 370 UpdateDisplay("400x400,200x200"); 371 EXPECT_EQ( 372 l10n_util::GetStringFUTF16( 373 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()), 374 GetDisplayNotificationText()); 375 376 // Mirroring. 377 CloseNotification(); 378 display_manager->SetSoftwareMirroring(true); 379 UpdateDisplay("400x400,200x200"); 380 EXPECT_EQ( 381 l10n_util::GetStringFUTF16( 382 IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName()), 383 GetDisplayNotificationText()); 384 385 // Back to extended. 386 CloseNotification(); 387 display_manager->SetSoftwareMirroring(false); 388 UpdateDisplay("400x400,200x200"); 389 EXPECT_EQ( 390 l10n_util::GetStringFUTF16( 391 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()), 392 GetDisplayNotificationText()); 393 394 // Resize the first display. 395 UpdateDisplay("400x400 (at) 1.5,200x200"); 396 EXPECT_EQ( 397 l10n_util::GetStringFUTF16( 398 IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, 399 GetFirstDisplayName(), UTF8ToUTF16("600x600")), 400 GetDisplayNotificationText()); 401 402 // rotate the second. 403 UpdateDisplay("400x400 (at) 1.5,200x200/r"); 404 EXPECT_EQ( 405 l10n_util::GetStringFUTF16( 406 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, 407 GetSecondDisplayName(), 408 l10n_util::GetStringUTF16( 409 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), 410 GetDisplayNotificationText()); 411 } 412 413 TEST_F(TrayDisplayTest, DisplayConfigurationChangedTwice) { 414 test::TestSystemTrayDelegate* tray_delegate = 415 static_cast<test::TestSystemTrayDelegate*>( 416 Shell::GetInstance()->system_tray_delegate()); 417 tray_delegate->set_should_show_display_notification(true); 418 419 UpdateDisplay("400x400,200x200"); 420 EXPECT_EQ( 421 l10n_util::GetStringUTF16( 422 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), 423 GetDisplayNotificationText()); 424 425 // OnDisplayConfigurationChanged() may be called more than once for a single 426 // update display in case of primary is swapped or recovered from dock mode. 427 // Should not remove the notification in such case. 428 tray_display()->OnDisplayConfigurationChanged(); 429 EXPECT_EQ( 430 l10n_util::GetStringUTF16( 431 IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), 432 GetDisplayNotificationText()); 433 434 // Back to the single display. It SHOULD remove the notification since the 435 // information is stale. 436 UpdateDisplay("400x400"); 437 EXPECT_TRUE(GetDisplayNotificationText().empty()); 438 } 439 440 TEST_F(TrayDisplayTest, UpdateAfterSuppressDisplayNotification) { 441 UpdateDisplay("400x400,200x200"); 442 443 test::TestSystemTrayDelegate* tray_delegate = 444 static_cast<test::TestSystemTrayDelegate*>( 445 Shell::GetInstance()->system_tray_delegate()); 446 tray_delegate->set_should_show_display_notification(true); 447 448 // rotate the second. 449 UpdateDisplay("400x400,200x200/r"); 450 EXPECT_EQ( 451 l10n_util::GetStringFUTF16( 452 IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, 453 GetSecondDisplayName(), 454 l10n_util::GetStringUTF16( 455 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), 456 GetDisplayNotificationText()); 457 } 458 459 } // namespace internal 460 } // namespace ash 461