Home | History | Annotate | Download | only in chromeos
      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