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