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